致命:c ++中不会重新抛出异常

时间:2016-01-24 06:29:52

标签: c++ linux multithreading

我试图在c ++中了解pthread_cancel在linux环境中的用法。但我遇到了运行时问题。

class A {
    public:
        A(){cout<<"constructor\n";}
        ~A(){cout<<"destructor\n";}
};
void* run(void* data) {
    A a;
    while(1) {
        //sleep(1);
        cout<<"while\n";
    }
}
int main() {
    pthread_t pid;
    pthread_create(&pid,NULL,run,NULL);
    sleep(2);;
    pthread_cancel(pid);
    cout<<"Canceled\n";
    pthread_exit(0);
}

输出:

   constructor 
    while 
    " 
    " 
    while 
    Canceled 
    FATAL: exception not rethrown 
    Aborted (core dumped)

核心文件分析:

(gdb) where
#0  0x00000036e8c30265 in raise () from /lib64/libc.so.6
#1  0x00000036e8c31d10 in abort () from /lib64/libc.so.6
#2  0x00000036e9c0d221 in unwind_cleanup () from /lib64/libpthread.so.0
#3  0x00000036fa69042b in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) () from /usr/lib64/libstdc++.so.6
#4  0x00000000004009c5 in run(void*) ()
#5  0x00000036e9c0677d in start_thread () from /lib64/libpthread.so.0
#6  0x00000036e8cd49ad in clone () from /lib64/libc.so.6

但是,如果我在线程函数运行中取消注释sleep(1),我的输出低于输出。     构造函数     而     取消     析

你能否解释一下为什么该计划正在给予&#34;致命:例外而不是重新投入&#34;在第一种情况下而不在第二种情况下请详细解释为什么pthread_cancel比pthread_kill更安全?

2 个答案:

答案 0 :(得分:1)

很抱歉成为坏消息的承担者,但要让pthread_cancel在Linux的C ++中正常工作很困难。

原因是Linux中的pthread_cancel方法实现绝对可怕。特别是它会引发异常(在我撰写本文时为abi::__forced_unwind)。这在C程序中可能很好,但是在C ++中,很难正确处理线程取消。特别是,如果您有任何吞噬异常的代码(例如catch (...)),则此内部异常将被处理并且不会按照需要的方式传递到堆栈中。在这种情况下,您将看到所看到的错误消息。

也就是说,我看不出您的代码中有什么会“吃掉”该异常,但是我怀疑是这种性质的问题导致了此问题。

在您的特定示例中,当您要退出而不调用pthread_cancel时,可以通过使用标志或类似便笺的方式轻松解决此问题。不幸的是,这使sleep变得更加复杂(您需要以很小的间隔多次调用它以检查标志),并且几乎不可能调用accept(必须从另一个端口连接到该端口)强制accept退出的线程或进程,以便您可以检查变量)。关于线程取消的一般问题(https://lwn.net/Articles/683118/)进行了很长的讨论,但是鉴于macOS(以及大概其他非Linux的“ unixes”)似乎处理得很好,我真的认为Linux实现可以做得更好。但是在完成该操作之前,pthread_cancel将仍然非常难以使用。

答案 1 :(得分:0)

我的猜测是,这与取消点有关。默认情况下,新线程具有取消类型PTHREAD_CANCEL_DEFERRED。这意味着pthread_cancel在线程点击其中一个预定义的取消点之前不会做任何事情。 sleep是已定义的取消点之一,但std::cout::operator<<不是(pthreads'手册页列出了所有取消点)。因此,当你的sleep注释掉时,线程永远不会到达取消点,而pthreads会抛出一个拟合。您可以使用pthread_setcanceltype将线程设置为PTHREAD_CANCEL_ASYNCHRONOUS,但这至少会导致我的系统出现问题。

您最好的选择可能是使用std::thread而不是直接处理pthreads。该库实际上是为了与C ++正常工作而设计的。