如何用goto模拟C语言中的异常?
我正在用 C 编写并发事务库并发现以下问题。 让我们考虑一个示例事务成员伪代码,其中“事务”代表与事务主控的通信通道:
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");
}
在并发事务中,只有当主控要求我们投票时,我们才能投票。 然而,master可以随时调用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_rcv
或 trans_send
编写 ifs 并不是很舒服,尤其是如果交易代码很复杂。 您有更好的解决方案吗?还是这是唯一的方法? 顺便说一句,它不必使用 goto
:)。
I'm writing a concurrent transaction library in C and found the following problem. Let's consider a sample transaction member pseudo-code, where the "transaction" represents a communication channel with the transaction master:
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");
}
In concurrent transactions, we can vote only if we are asked for the vote by the master. However, the master can call trans_abort(member)
at any time, forcing the specified member to cancel the transaction. The ABORT message can be received by the member at any stage of execution and in this case unsually it should not wait till the execution reaches trans_ready()
call. For example, if there is a trans_rcv()
call in the later code, the process would hang on waiting for the data from the master which will be never sent.
Now, the point. I have already the code to register the aborting function that rolls back the changes, but I would also like to have an extra mechanism that would allow to skip the rest of the remaining operations and jump to the voting code immediately. I have an idea to use goto here to simulate exceptions:
if(!trans_rcv()) /* fail, we received the abort message */
{
goto abort_code;
}
...
abort_code:
trans_ready(transaction);
/* etc. */
However, writing ifs for every call of trans_rcv
or trans_send
is not very comfortable, especially if the transaction code is complex. Have you got any idea for a better solution or is this the only way? It does not have to use goto
, by the way :).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
goto
只能在一个函数内部工作,这对于异常机制来说可能是一个太大的限制。我建议使用
setjmp
/longjmp
函数 - 请参阅 维基百科了解详细信息。goto
works only inside one function, which is probably too much a limitation for exception mechanism.I'd suggest to use
setjmp
/longjmp
functions - see Wikipedia for details.如果输入 IF 是问题,您可以使用宏,例如:
如果 trans_rcv 有参数,这应该可以工作(至少在 gcc 中):
If typing the IFs is the problem, you could use a macro, like:
If trans_rcv has parameters, this should work (in gcc, at least):
就我个人而言,我会使用 while 循环来编写此代码,其中包含基于开关的状态机。
Personally I would code this by using a while loop with a switch based state machine inside of it.
C 中的异常处理的最佳来源之一。 基本上 RTOS 的人们如何为其 RTFile 模块实现异常。 当心文章后半部分可怕的汇编语言。
One of the best source for exception handling in C. Basically how people at RTOS implemented exceptions for their RTFile module. Beware of the dreadful slip into assembly language past the second half of the article.
请参阅 Hanson 的“C 接口和实现:创建可重用软件的技术”。 它提供了基于
setjmp()
和longjmp()
的异常机制。 该代码可通过 MIT 许可证获得。See Hanson's "C Interfaces and Implementations: Techniques for Creating Reusable Software". It provides an exception mechanism based on
setjmp()
andlongjmp()
. The code is available with an MIT licence.