【发布时间】:2017-01-13 03:26:41
【问题描述】:
按ctrl+c时出现以下错误
^Cctrl-c
terminate called without an active exception
Aborted (core dumped)
这里是 gdb stackstrace:
(gdb) bt
#0 0x0000003a47432625 in raise () from /lib64/libc.so.6
#1 0x0000003a47433e05 in abort () from /lib64/libc.so.6
#2 0x0000003a4a46007d in __gnu_cxx::__verbose_terminate_handler () at ../../.././libstdc++-v3/libsupc++/vterminate.cc:95
#3 0x0000003a4a45e0e6 in __cxxabiv1::__terminate (handler=<optimized out>) at ../../.././libstdc++-v3/libsupc++/eh_terminate.cc:47
#4 0x0000003a4a45e131 in std::terminate () at ../../.././libstdc++-v3/libsupc++/eh_terminate.cc:57
#5 0x000000000040172f in std::thread::~thread() ()
#6 0x00000000004036ad in void std::_Destroy<std::thread>(std::thread*) ()
#7 0x0000000000403396 in void std::_Destroy_aux<false>::__destroy<std::thread*>(std::thread*, std::thread*) ()
#8 0x000000000040311c in void std::_Destroy<std::thread*>(std::thread*, std::thread*) ()
#9 0x0000000000402dd6 in void std::_Destroy<std::thread*, std::thread>(std::thread*, std::thread*, std::allocator<std::thread>&) ()
#10 0x000000000040415b in std::vector<std::thread, std::allocator<std::thread> >::~vector() ()
#11 0x0000003a47435b22 in exit () from /lib64/libc.so.6
#12 0x000000000040142b in f(int) ()
#13 <signal handler called>
#14 0x0000003a478082fb in pthread_join () from /lib64/libpthread.so.0
#15 0x0000003a4a4bb627 in __gthread_join (__value_ptr=0x0, __threadid=<optimized out>)
at /root/tmp/gcc-4.9.3/x86_64-unknown-linux-gnu/libstdc++-v3/include/x86_64-unknown-linux-gnu/bits/gthr-default.h:668
#16 std::thread::join (this=<optimized out>) at ../../../.././libstdc++-v3/src/c++11/thread.cc:107
#17 0x0000000000401540 in t2() ()
#18 0x0000000000401585 in main ()
这是代码:
vector<thread*> v1;
vector<thread> v2;
void task1(std::string msg){
while (1) {
cout << "task1 says: " << msg << endl;
sleep(2);
}
}
void ctrl_c(int s)
{
cout << "ctrl-c\n";
exit(0);
}
void func1()
{
for (int i=0; i<3; i++) {
v1.push_back(new thread(task1, "v1"));
}
for (int i=0; i<3; i++) {
v1[i]->join();
}
}
void func2()
{
#ifndef GLOBAL
vector<thread> v2;
#endif
for (int i=0; i<3; i++) {
v2.push_back(thread(task1, "bad global v2"));
}
for (int i=0; i<3; i++) {
v2[i].join();
}
}
int main() {
signal(SIGINT,ctrl_c);
//func1();
//func2();
return 0;
}
注意v1是全局向量,包含线程指针; v2是全局向量,包含线程对象
当我只运行func1时,程序是ok的;
当我只运行 func2 时,情况会有所不同,具体取决于命令行上是否给出了 GLOBAL 选项。给定时,程序正常,不给定时,会发生上述异常。此外,如果我注释掉signal(SIGINT,ctrl_c),ctrl+c 不会导致异常。(所以我猜exit 调用会导致全局矢量对象破坏,对吧?)
所以我的问题是:这些条件之间有什么区别?在func2条件下,如果我想捕获SIGINT并在其信号处理程序中调用exit,同时我想使用全局vector<thread>,我应该如何避免按ctrl+c时出现异常?
谢谢
【问题讨论】:
-
是的,
exit()调用全局对象的析构函数。~std::thread()析构函数调用terminate()如果被销毁的线程之前没有加入或分离。这就是你观察到的。 -
@IgorTandetnik 但是为什么堆栈跟踪停止在
pthread_join,因为它没有加入? -
@scottxiao 创建了三个线程;这三个都运行一个无限循环。
join第一次被调用,但由于线程没有终止,所以该调用将永远等待。虽然join被阻止(显然在pthread_join内部,但这是一个内部实现细节),但用户按下 Ctrl+C,它运行信号处理程序,它调用exit(),这会破坏全局变量 - 包括其他两个thread没有调用join的对象。 -
@IgorTandetnik 是在 Linux 进程的随机线程上调用的信号处理程序吗?如果是这样,堆栈跟踪可能每次看起来都不一样。
-
@scottxiao 不知道。我自己就是一个 Windows 人。在 Windows 中,它在同一进程中的单独线程上调用。问题中显示的堆栈跟踪似乎表明信号在主线程上运行 - 与调用
join的线程相同 - 但就像我说的,我真的不知道我在说什么;至少,不在实施层面。
标签: c++ multithreading exception