致命:异常未在 C++ 中重新抛出
Posted
技术标签:
【中文标题】致命:异常未在 C++ 中重新抛出【英文标题】:FATAL: exception not rethrown in c++ 【发布时间】:2016-01-24 06:29:51 【问题描述】:我正在尝试了解 pthread_cancel 在 c++ 中的 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
...
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),我会得到低于输出。
constructor
while
Canceled
destructor
您能否解释一下为什么程序在第一种情况下而不是在第二种情况下给出“致命:异常未重新抛出”?并请举例详细解释为什么pthread_cancel比pthread_kill更安全?
【问题讨论】:
几件事:1.)不要在主线程上调用pthread_exit
,如果调用,在创建的线程中进行;这可能是你的问题。 2)什么版本? Pthread 可以是特定于平台的(例如,这在 BSD 上“按预期”工作)。 3.) 您的gdb
输出用于线程,因此堆栈将在cout << "while\n"
上显示它“崩溃”,执行thread apply all
并显示主线程的堆栈。 4.) 问:..explain..in 1st not in 2nd?
,答:定时 5.) 问:why pthread_cancel and pthread_kill
,答:neither
【参考方案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 “unix”)似乎处理得很好,我真的认为 Linux 实现可以做得更好.但在此之前,pthread_cancel 仍然很难使用。
【讨论】:
【参考方案2】:我的猜测是这与取消点有关。新线程默认具有取消类型PTHREAD_CANCEL_DEFERRED
。这意味着pthread_cancel
在线程到达预定义的取消点之一之前不会做任何事情。 sleep
是定义的取消点之一,但std::cout::operator<<
不是(pthreads 的手册页列出了所有取消点)。因此,当您将 sleep
注释掉时,线程永远不会达到取消点,并且 pthreads 会出现故障。您也许可以使用pthread_setcanceltype
将线程设置为PTHREAD_CANCEL_ASYNCHRONOUS
,但这至少会导致我的系统出现问题。
您最好的选择可能是使用std::thread
而不是直接处理pthread。该库实际上旨在与 C++ 一起正常工作。
【讨论】:
以上是关于致命:异常未在 C++ 中重新抛出的主要内容,如果未能解决你的问题,请参考以下文章
EclipseLink DataModifyQuery 不会抛出致命异常
致命错误:第 19 行的 C:\xampp\htdocs\register.php 中抛出未捕获的异常“PDOException”