C++异常和信号处理程序
我正在阅读 Bjarne Stroustrup 所著的《C++ 的设计与演化》。关于异常处理和异步信号如下:
异常可以用来处理信号之类的事情吗?几乎可以肯定,在大多数 C 环境中都不会。问题是 C 使用像 malloc 这样的不可重入函数。如果在malloc中间发生中断并导致异常,则无法阻止异常处理程序再次执行malloc。
一个 C++ 实现,其中调用序列和整个运行时库是围绕可重入的要求而设计的,这使得信号可以抛出异常
作者所说的“没有办法阻止异常处理程序”是什么意思?再次执行malloc”?使函数可重入如何使信号处理程序抛出异常成为可能?
I am reading The Design and Evolution of C++, by Bjarne Stroustrup. Regarding exeception handling and asynchronous signals it is mentioned as below:
Can exceptions be used to handle things like signals? Almost certainly not in most C environments. The trouble is that C uses functions like malloc that are not re-entrant. If an interrupt occurs in the middle of malloc and causes an exception, there is no way to prevent the exception handler from executing malloc again.
A C++ implementation where calling sequences and the entire run-time library are designed around the requirement for re-entrancy would make it possible for signals to throw exceptoins
What does the author mean by the statement "there is no way to prevent the exception handler from executing malloc again"? How would making functions re-entrant make it possible to throw exceptions from signal handlers?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在我看来,这部分对于当前的 C++ 来说并没有多大意义。
在 C++ 中,无法将异常用作信号,因为信号意味着执行处理程序,然后(可能)继续执行。
然而,C++ 异常不是这样工作的。一旦到达异常处理程序,堆栈就已经回滚,并且在处理后无法“继续”:无法到达抛出后的语句(或在发生异常的函数调用后)抛出)。
信号是异步的,但不会造成破坏,并且在信号可能后继续(即使当然必须注意信号处理程序中所做的事情),异常反而会破坏程序流程,并且不可能继续。
我想说这两个想法在逻辑层面上是不兼容的,并且库是否可重入并不重要。
可能在早期的 C++ 设计中,有一个针对异常的恢复选项......
In my opinion that part doesn't really make much sense with current C++.
In C++ there is no way to use an exception as a signal because signals are meant to be executing an handler and then (possibly) continue execution.
C++ exceptions however don't work this way. Once you get to the exception handler the stack has been already rolled back and there is no way to "continue" after the handling: there is no way to get to the statement following a throw (or following a function call during which an exception gets thrown).
Signals are asynchronous but not disruptive and continuing after a signal is possible (even if of course care must be taken about what is done in the signal handler), exceptions instead are disruptive of the program flow and continuing is impossible.
I'd say the two ideas are incompatible at a logical level and doesn't really matter if the library is reentrant or not.
May be in early C++ design there was a resume option for exceptions...
例如,如果对 malloc 的调用引发了一个信号,那么如果您从该信号处理程序抛出异常,则异常抛出逻辑可能会再次调用 malloc。由于 malloc 不可重入,您最终会遇到未定义的行为。
处理信号的一种方法是将信号事件推入事件队列并立即从信号处理程序返回。然后,当事件循环处理信号事件时,它可以做任何它想做的事情,因为它不在信号处理程序的受限上下文中。
If for example, a call to malloc induced a signal then if you threw an exception from that signal handler malloc could be called again by the exception throwing logic. Since malloc isn't reentrant you'd wind up with undefined behavior.
One way to deal with signals is to just push a signal event into your event queue and return from the signal handler immediately. Then when the event loop processes the signal event it can do whatever it wants since it isn't in the restricted context of a signal handler.
如果一个函数可以在执行过程中中断并在中断的调用完成之前再次调用,则该函数是“可重入的”。另一种看待它的方式是:可以从信号处理程序中调用可重入函数。所有的赌注都集中在从信号处理程序中调用不可重入函数。唯一应该从信号处理程序内部调用的函数是那些已知可重入的函数。
malloc 是不可重入的。如果 malloc 发生 kaboom,则无法判断它是否在更新 malloc 在幕后使用以跟踪分配的数据的任何全局数据的过程中发生 kaboom。
信号处理程序与异常的另一个问题是:在信号处理程序中执行的代码本质上是在与主代码不同的线程中运行。 如果信号可以被寻址,则信号处理程序的返回将返回到发出信号的点之后。您将如何在信号处理程序中引发异常?这样做,信号处理程序将不再返回!这意味着其余的执行是在信号处理程序中有效完成的。现在当另一个信号出现时会发生什么?这两个概念不能混为一谈。可重入只是这里的冰山一角。
A function is "reentrant" if it can be interrupted in the middle of execution and called again before that interrupted call completes. Another way to look at it: A reentrant function can be called from within a signal handler. All bets are off on calling a non-reentrant function from within a signal handler. The only functions that should be called from inside a signal handler are those functions that are known to be reentrant.
malloc is not reentrant. If malloc goes kaboom there is no way of telling if it went kaboom in the middle of updating whatever global data malloc uses behind the scenes to keep track of allocated data.
Another problem with signal handlers versus exceptions: Code executing in a signal handler is essentially running in a different thread than the main code. If the signal can be addressed, a return from the signal handler returns to just after the point where the signal was raised. How are you going to throw an exception in a signal handler? Do that and the signal handler is no longer returning! That means the rest of the execution is effectively done from within the signal handler. Now what happens when another signal occurs? The two concepts just don't mix. Reentrancy is just the tip of the iceberg here.