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

时间:2009-06-03 09:26:18

标签: c exception goto

我在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");
}

在并发交易中,我们只有在要求主人投票时才能投票。但是,主服务器可以随时调用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. */

但是,为trans_rcvtrans_send的每次通话编写 ifs 都不太舒服,尤其是在交易代码很复杂的情况下。你有没有想过更好的解决方案,还是这是唯一的方法?顺便说一句,它不必使用goto。)。

5 个答案:

答案 0 :(得分:7)

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

我建议使用setjmp / longjmp函数 - 有关详细信息,请参阅Wikipedia

答案 1 :(得分:5)

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

#define trans_rcv_CHK do { \
     if (!trans_rcv()) \
     { \
          goto abort_code; \
     } \
} while(0)

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

#define trans_rcv_CHK(...) do { \
     if (!trans_rcv(__VA_ARGS__)) \
     { \
          goto abort_code; \
     } \
} while (0)

答案 2 :(得分:3)

就我个人而言,我会使用一个带有基于开关的状态机的while循环对其进行编码。

答案 3 :(得分:3)

exception handling in C的最佳来源之一。基本上,RTOS的人们如何为他们的RTFile模块实现异常。在文章的后半部分,要注意可怕的汇编语言。

答案 4 :(得分:1)

见汉森的“C Interfaces and Implementations: Techniques for Creating Reusable Software”。它提供了基于setjmp()longjmp()的异常机制。该代码可通过MIT许可证获得。