博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
线程与异常
阅读量:6113 次
发布时间:2019-06-21

本文共 5576 字,大约阅读时间需要 18 分钟。

最近遇到了一个c++线程抛出异常的问题

代码片段

#include 
#include
#include
#include
#include
#include
#include
using namespace std;vector
v1;vector
v2;void task1(std::string msg){ while (1) { cout << "task1 says: " << msg << endl; sleep(2); }}void f(int s){ cout << "ctrl-c\n"; exit(0);}void t1(){ for (int i=0; i<3; i++) { v1.push_back(new thread(task1, "hello")); } for (int i=0; i<3; i++) { v1[i]->join(); }}void t2(){ for (int i=0; i<3; i++) { v2.push_back(thread(task1, "hello")); } for (int i=0; i<3; i++) { v2[i].join(); }}int main() { signal(SIGINT,f); //t1(); t2(); return 0;}

以上代码,单独执行t1,正常;单独执行t2,期间ctrl+c停止时,就会抛出异常:

terminate called without an active exception

Aborted (core dumped)

但如果把vector v2放进main中,就没问题了;或者去掉SIGINT信号的捕获,也正常;

这个情况,该如何解释呢?

gdb 结果

(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=
) 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*) ()#7 0x0000000000403396 in void std::_Destroy_aux
::__destroy
(std::thread*, std::thread*) ()#8 0x000000000040311c in void std::_Destroy
(std::thread*, std::thread*) ()#9 0x0000000000402dd6 in void std::_Destroy
(std::thread*, std::thread*, std::allocator
&) ()#10 0x000000000040415b in std::vector
>::~vector() ()#11 0x0000003a47435b22 in exit () from /lib64/libc.so.6#12 0x000000000040142b in f(int) ()#13
#14 0x0000003a478082fb in pthread_join () from /lib64/libpthread.so.0#15 0x0000003a4a4bb627 in __gthread_join (__value_ptr=0x0, __threadid=
) 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=
) at ../../../.././libstdc++-v3/src/c++11/thread.cc:107#17 0x0000000000401540 in t2() ()#18 0x0000000000401585 in main ()

首先v2是全局变量,按ctrl+c就会执行exit,v2要析构,就导致thread对象要析构,但此时它们都是joinable状态,析构函数会调用terminate

把v2作为局部变量就没问题了,不会导致vector析构被调用

关于joinable

Checks if the thread object identifies an active thread of execution. Specifically, returns true if get_id() != std::thread::id(). So a default constructed thread is not joinable.

A thread that has finished executing code, but has not yet been joined is still considered an active thread of execution and is therefore joinable. 【已经完成了,但还没有被joined,则仍是一个执行线程,仍是joinable】

测试代码:

#include 
#include
#include
void foo(){ std::this_thread::sleep_for(std::chrono::seconds(1));}int main(){ std::thread t; std::cout << "before starting, joinable: " << t.joinable() << '\n';//0 t = std::thread(foo); std::cout << "after starting, joinable: " << t.joinable() << '\n';//1 t.join(); std::cout << "after joining, joinable: " << t.joinable() << '\n';//0}

关于线程的析构函数

要点:

  • 当前线程实例有关联的线程,也就是joinable,则析构调用terminate
  • 当前线程实例在以下情况下没有关联的线程(都不是joinable)
    • 刚刚创建
    • 被moved
    • join已经调用
    • detach已经调用

来自stackoverflow网友

The destructor for std::thread will call std::terminate if it is run on a thread if you not have called join() (to wait the thread to finish) or detach() (to detach the thread from the object) on it. Thus the programmer must ensure that the destructor is never executed while the thread is still joinable

When a thread object goes out of scope and it is in joinable state, the program is terminated. The Standard Committee had two other options for the destructor of a joinable thread. It could quietly join – but join might never return if the thread is stuck. Or it could detach the thread (a detached thread is not joinable). However, detached threads are very tricky, since they might survive till the end of the program and mess up the release of resources. So if you don’t want to terminate your program, make sure you join (or detach) every thread.

Once a thread has been started within a scope (which itself is running on a thread), one must explicitly ensure one of the following happens before the thread goes out of scope:

  • The runtime exits the scope, only after that thread finishes executing. This is achieved by joining with that thread. Note the language, it is the outer scope that joins with that thread.
  • The runtime leaves the thread to run on its own. So, the program will exit the scope, whether this thread finished executing or not. This thread executes and exits by itself. This is achieved by detaching the thread. This could lead to issues, for example, if the thread refers to variables in that outer scope.

Note, by the time the thread is joined with or detached, it may have well finished executing. Still either of the two operations must be performed explicitly.

这位网友的代码如下:

void userStop(bool *st) {    char chChar = getchar();    if(chChar == '\n') {        *st = true;    }}void func3(){    bool stopper = false;    thread stopThread(userStop, &stopper);      // start thread looking for user input    for(int i = 0; i < 1000; i++) {        if(stopper) { break; }                  // break if desired        // Do stuff        //sleep(2);    }}

问题在于stopThread离开作用域导致析构,而此时它仍是joinable(在等待用户输入)

有用的链接

转载地址:http://hrjka.baihongyu.com/

你可能感兴趣的文章
最近公共祖先(lca)
查看>>
【WP 8.1开发】文件选取器的使用方法
查看>>
Java实现BASE64编解码
查看>>
【Java】java基本知识
查看>>
之前学习wordpress的几张图片
查看>>
RT-Thread下的串口驱动程序分析【转载】
查看>>
UITableView的UITableViewStyleGrouped
查看>>
ecshop中getAll ,getOne ,getRow的区别
查看>>
luov之SMTP报错详解
查看>>
软件概要设计做什么,怎么做
查看>>
dwr
查看>>
java的特殊符号
查看>>
word2010中去掉红色波浪线的方法
查看>>
fabric上下文管理器(context mangers)
查看>>
JQuery-EasyUI Datagrid数据行鼠标悬停/离开事件(onMouseOver/onMouseOut)
查看>>
并发和并行的区别
查看>>
JS数据结构学习:队列
查看>>
浙江信访,从统一到智能的互联网转型之路
查看>>
对是否要用Linux的思考
查看>>
「每日一瞥
查看>>