如何使用goto模拟C中的异常?

Zyx*_*Zyx 0 c goto exception

我在C中编写并发事务库,发现了以下问题.让我们考虑一个示例事务成员伪代码,其中"transaction"表示与事务主机的通信通道:

transaction = trans_join();

do_some_ops();

/* receive the data from the master */
trans_rcv(transaction, data);

do_some_ops();

trans_send(transaction, answer);

/* wait for the possibility for voting */
trans_ready(transaction);

/* vote for commiting and wait for the voting results. */
if(trans_commit(answer))
{
   printf("Final commiting the changes.\n");
}
else
{
   printf("Rolling back the changes.\n");
}
Run Code Online (Sandbox Code Playgroud)

在并发交易中,我们只有在被要求主人投票时才能投票.但是,主服务器可以随时调用trans_abort(member),强制指定的成员取消该事务.成员在执行的任何阶段都可以接收ABORT消息,在这种情况下,它不应该等到执行到达trans_ready()呼叫.例如,如果trans_rcv()在后面的代码中有一个调用,则该进程将在等待来自主服务器的数据时挂起,该数据将永远不会被发送.

现在,重点.我已经在代码注册中止功能回滚的变化,但我也想有一个额外的机制,让跳过其余操作的其余部分,并立即跳转到投票代码.我有一个想法,在这里使用goto来模拟异常:

if(!trans_rcv()) /* fail, we received the abort message */
{
   goto abort_code;
}

...

abort_code:
trans_ready(transaction);
/* etc. */
Run Code Online (Sandbox Code Playgroud)

但是,为每次调用编写ifstrans_rcv或者trans_send不太舒服,特别是如果事务代码很复杂.你有没有想过更好的解决方案,还是这是唯一的方法?goto顺便说一句,它不必使用:).

qrd*_*rdl 7

goto 仅在一个函数内部工作,这可能是对异常机制的一个限制.

我建议使用setjmp/ longjmpfunctions - 有关详细信息,请参阅Wikipedia.


tsg*_*tsg 5

如果键入IF是问题,您可以使用宏,如:

#define trans_rcv_CHK do { \
     if (!trans_rcv()) \
     { \
          goto abort_code; \
     } \
} while(0)
Run Code Online (Sandbox Code Playgroud)

如果trans_rcv有参数,这应该有效(至少在gcc中):

#define trans_rcv_CHK(...) do { \
     if (!trans_rcv(__VA_ARGS__)) \
     { \
          goto abort_code; \
     } \
} while (0)
Run Code Online (Sandbox Code Playgroud)

  • 确保将if包含在do中,同时将false包装.那就是你最后用分号调用trans_rcv_CHK而不会产生任何意想不到的后果.请参阅:http://c2.com/cgi/wiki/Wiki?TrivialDoWhileLoop (2认同)