2017-06-27 57 views
1

我正在测试pthread_cancel的工作方式。linux上的pthread_cancel()会导致exception/coredump,为什么?

#include<pthread.h> 
#include<unistd.h> 
#include<iostream> 
using namespace std; 
int retval=70; 
void* tf(void*arg){ 
    int oldstate; 
    int i=0; 
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); 
    while(true){ 
     cout<<"sleep 1"<<endl; 
     sleep(1); 
     ++i; 
     if(i==5){//response to last pthread_cancel()? 
      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); 
     } 
    } 
    return NULL; 
} 
int main(){ 
    pthread_t tid; 
    pthread_create(&tid,NULL,tf,NULL); 
    sleep(2); 
    pthread_cancel(tid);//not responded until "PTHREAD_CANCEL_ENABLE"? 
    cout<<"cancel thread"<<endl; 
    pthread_join(tid,NULL); 
    return 0; 
} 

我预计

(1)当cancallation被禁用时,pthread_cancel可以任意的通话将被忽略,但通话将被铭记

(2),直至取消已启用:它会检查是否有先前的pthread_cancel调用,如果是,则取消完成。

sleep 1 
sleep 1 
cancel thread 
sleep 1 
sleep 1 
sleep 1 
sleep 1 

但我的Linux服务器上,它打印:

sleep 1 
sleep 1 
cancel thread 
sleep 1 
sleep 1 
sleep 1 
FATAL: exception not rethrown 
sleep 1 
Aborted (core dumped) 

只要有不知道发生了什么实际工作,以及严重异常是怎么扔? 我应该有一些错误的理解。需要你的建议!

+0

与你的问题无关,但是如果你声明了一个函数来返回一些东西,你应该真的返回一些东西,即使它只是一个简单的'return NULL;' –

+0

只修复了缺失的返回值-----仍然是我所描述的同样的问题。 –

回答

1

线程取消点和C++互相不协调。想想当线程被取消时线程堆栈中的局部变量会发生什么,它们的析构函数会被调用。

从历史上看,对此有一些争论,许多pthread实现选择不同。有些人甚至会用与C++异常相同的机制来实现取消,这样堆栈就会很好地解开。但随后,井周围放置catch会搞乱的东西...

但随后,pthread_cancel是一个POSIX结构,因而只为好C.

也就是说定义,编译器尽量做到最好。就你而言,它可能是你的编译器或库中的一个bug(你不会说你正在使用什么编译器版本和编译器命令......)。你的代码适合我(GCC 7.1和Clang 4.0.1)。

但是如果我添加一个try/catch这样的,它不能跟你的一样:

void* tf(void*arg) { 
    try { 
     //your code 
    } catch (...) { 
     return NULL; 
    } 
} 

但是,如果我重新抛出异常的catch结束它的工作再细:

void* tf(void*arg) { 
    try { 
     //your code 
    } catch (...) { 
     throw; 
    } 
} 

这证明在我的C++编译器pthread_cancel中使用与C++异常相同的机制。我的猜测是,当线程在C++模式下被取消时,它会抛出一个内部异常,并期望在线程函数的父节点处捕获它。但是,如果您通常从线程函数返回,那么当该线程被取消时,将显示此消息。

而且因为你没有做的这事,有几种解释:

  • 您正在使用不支持C++和并行线程取消一个编译器。
  • 您的编译器/库版本中存在一个错误。
  • 您正在混合不同版本的编译器/库。或者,也许你在混合使用C和C++库。

PS 1:我检查添加本地变量与非平凡的析构函数给线程函数,和本人确认析构函数时调用的线程结束。

PS 2:我检查了从线程函数调用pthread_exit(),没有取消,并且也调用了局部析构函数。如果我在pthread_exit()附近执行try/catch(...),则它会以相同的FATAL: exception not rethrown失败。所以pthread_exit()pthread_cancel()使用相同的底层机制。

PS 3:所有这一切看起来很不错,但仍然会发生线程取消在任何一点:如果线程取消在cout.operator<<()中间发生那么任何进一步写入该流(从本地析构函数,例如)根本无法工作。

1

它在运行Linux的PC上工作正常。

$ g++ try.cc -o try -lpthread 
$ ./try 
sleep 1 
sleep 1 
cancel thread 
sleep 1 
sleep 1 
sleep 1 
sleep 1 
$ 
相关问题