未处理的强制展开导致中止

发布于 2024-10-13 14:17:27 字数 2213 浏览 3 评论 0原文

因此,我对 pthread_exit 和 pthread_cancel 的理解是,它们都会导致称为“强制展开”的类似异常的事情被抛出目标中的相关堆栈帧线。可以捕获它以进行特定于线程的清理,但必须重新抛出,否则我们会在 catch 块末尾得到一个隐式的 abort() ,而该块不会重新抛出扔。

对于 pthread_cancel 来说,这种情况要么在收到关联信号时立即发生,要么在下一次进入取消点时发生,或者在信号下次解除阻塞时发生,具体取决于线程的取消状态和类型。

pthread_exit的情况下,调用线程立即进行强制展开。

美好的。这个“异常”是杀死线程过程中的正常部分。那么,为什么即使我重新抛出它,它也会导致 std::terminate() 被调用,从而中止我的整个应用程序?

请注意,我多次捕获并重新抛出异常。

另请注意,我正在从我的 SIGTERM 信号处理程序中调用 pthread_exit。这在我的玩具测试代码中工作得很好,用 g++ 4.3.2 编译,它有一个线程运行 signal(SIGTERM, handler_that_calls_pthread_exit) 然后坐在一个紧密的 while 循环中,直到它收到 TERM 信号。但在实际应用中却行不通。

相关堆栈框架:

(gdb) where
#0  0x0000003425c30265 in raise () from /lib64/libc.so.6
#1  0x0000003425c31d10 in abort () from /lib64/libc.so.6
#2  0x00000000012b7740 in sv_bsd_terminate () at exception_handlers.cpp:38
#3  0x00002aef65983aa6 in __cxxabiv1::__terminate (handler=0x518)
    at /view/ken_gcc_4.3/vobs/Compiler/gcc/libstdc++-v3/libsupc++/eh_terminate.cc:43
#4  0x00002aef65983ad3 in std::terminate ()
    at /view/ken_gcc_4.3/vobs/Compiler/gcc/libstdc++-v3/libsupc++/eh_terminate.cc:53
#5  0x00002aef65983a5a in __cxxabiv1::__gxx_personality_v0 (
    version=<value optimized out>, actions=<value optimized out>, 
    exception_class=<value optimized out>, ue_header=0x645bcd80, 
    context=0x645bb940)
    at /view/ken_gcc_4.3/vobs/Compiler/gcc/libstdc++-v3/libsupc++/eh_personality.cc:657
#6  0x00002aef6524d68c in _Unwind_ForcedUnwind_Phase2 (exc=0x645bcd80, 
    context=0x645bb940)
    at /view/ken_gcc_4.3/vobs/Compiler/gcc/libgcc/../gcc/unwind.inc:180
#7  0x00002aef6524d723 in _Unwind_ForcedUnwind (exc=0x645bcd80, 
    stop=<value optimized out>, stop_argument=0x645bc1a0)
    at /view/ken_gcc_4.3/vobs/Compiler/gcc/libgcc/../gcc/unwind.inc:212
#8  0x000000342640cf80 in __pthread_unwind () from /lib64/libpthread.so.0
#9  0x00000034264077a5 in pthread_exit () from /lib64/libpthread.so.0
#10 0x0000000000f0d959 in threadHandleTerm (sig=<value optimized out>)
    at osiThreadLauncherLinux.cpp:46
#11 <signal handler called>

谢谢!

埃里克

So my understanding of both pthread_exit and pthread_cancel is that they both cause an exception-like thing called a "forced unwind" to be thrown out of the relevant stack frame in the target thread. This can be caught in order to do thread-specific clean-up, but must be re-thrown or else we get an implicit abort() at the end of the catch block that didn't re-throw.

In the case of pthread_cancel, that happens either immediately on receipt of the associated signal, or the next entry into a cancellation point, or when the signal is next unblocked, depending on the thread's cancellation state and type.

In the case of pthread_exit, the calling thread immediately undergoes a forced unwind.

Fine. This "exception" is a normal part of the process of killing a thread. So why, even when I re-throw it, is it causing std::terminate() to be called, aborting my whole application?

Note that I'm catching and re-throwing the exception a couple times.

Note also that I'm calling pthread_exit out of my SIGTERM signal handler. This works fine in my toy test code, compiled with g++ 4.3.2, which has a thread run signal(SIGTERM, handler_that_calls_pthread_exit) and then sit in a tight while loop until it gets the TERM signal. But it doesn't work in the real application.

Relevant stack frames:

(gdb) where
#0  0x0000003425c30265 in raise () from /lib64/libc.so.6
#1  0x0000003425c31d10 in abort () from /lib64/libc.so.6
#2  0x00000000012b7740 in sv_bsd_terminate () at exception_handlers.cpp:38
#3  0x00002aef65983aa6 in __cxxabiv1::__terminate (handler=0x518)
    at /view/ken_gcc_4.3/vobs/Compiler/gcc/libstdc++-v3/libsupc++/eh_terminate.cc:43
#4  0x00002aef65983ad3 in std::terminate ()
    at /view/ken_gcc_4.3/vobs/Compiler/gcc/libstdc++-v3/libsupc++/eh_terminate.cc:53
#5  0x00002aef65983a5a in __cxxabiv1::__gxx_personality_v0 (
    version=<value optimized out>, actions=<value optimized out>, 
    exception_class=<value optimized out>, ue_header=0x645bcd80, 
    context=0x645bb940)
    at /view/ken_gcc_4.3/vobs/Compiler/gcc/libstdc++-v3/libsupc++/eh_personality.cc:657
#6  0x00002aef6524d68c in _Unwind_ForcedUnwind_Phase2 (exc=0x645bcd80, 
    context=0x645bb940)
    at /view/ken_gcc_4.3/vobs/Compiler/gcc/libgcc/../gcc/unwind.inc:180
#7  0x00002aef6524d723 in _Unwind_ForcedUnwind (exc=0x645bcd80, 
    stop=<value optimized out>, stop_argument=0x645bc1a0)
    at /view/ken_gcc_4.3/vobs/Compiler/gcc/libgcc/../gcc/unwind.inc:212
#8  0x000000342640cf80 in __pthread_unwind () from /lib64/libpthread.so.0
#9  0x00000034264077a5 in pthread_exit () from /lib64/libpthread.so.0
#10 0x0000000000f0d959 in threadHandleTerm (sig=<value optimized out>)
    at osiThreadLauncherLinux.cpp:46
#11 <signal handler called>

Thanks!

Eric

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

笑着哭最痛 2024-10-20 14:17:27

另请注意,我正在打电话
pthread_exit 退出我的 SIGTERM 信号
处理程序。

这是你的问题。引用 POSIX 规范 (http://pubs.opengroup.org/onlinepubs/009695399/functions/signal.html):

如果信号不是由于调用 abort()、raise()、kill()、pthread_kill() 或 sigqueue() 而发生的,并且信号处理程序行为未定义指具有静态存储持续时间的任何对象,除了为声明为 volatile sig_atomic_t 的对象赋值之外,或者如果信号处理程序调用标准库中除信号概念中列出的函数之一之外的任何函数。


允许的函数列表位于 http://pubs.opengroup.org/ onlinepubs/009695399/functions/xsh_chap02_04.html#tag_02_04_03,并且不包含 pthread_exit()。因此,您的程序表现出未定义的行为。

我可以想到三种选择:

  1. 在信号处理程序中设置一个标志,由线程定期检查该标志,而不是尝试直接从信号处理程序退出。
  2. 使用 sigwait() 显式等待独立线程上的信号。然后,该线程可以在您希望退出的线程上显式调用pthread_cancel()
  3. 屏蔽信号,并在要退出的线程上定期调用 sigpending() ,如果信号处于挂起状态则退出。

Note also that I'm calling
pthread_exit out of my SIGTERM signal
handler.

This is your problem. To quote from the POSIX specs (http://pubs.opengroup.org/onlinepubs/009695399/functions/signal.html):

If the signal occurs other than as the result of calling abort(), raise(), kill(), pthread_kill(), or sigqueue(), the behavior is undefined if the signal handler refers to any object with static storage duration other than by assigning a value to an object declared as volatile sig_atomic_t, or if the signal handler calls any function in the standard library other than one of the functions listed in Signal Concepts.

The list of permitted functions is given at http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html#tag_02_04_03, and does not include pthread_exit(). Therefore your program is exhibiting undefined behaviour.

I can think of three choices:

  1. Set a flag in the signal handler which is checked by the thread periodically, rather than trying to exit directly from the signal handler.
  2. Use sigwait() to explicitly wait for the signal on an independent thread. This thread can then explicitly call pthread_cancel() on the thread you wish to exit.
  3. Mask the signal, and call sigpending() periodically on the thread that is to be exited, and exit if the signal is pending.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文