简体   繁体   English

linux上的pthread_cancel()导致异常/ coredump,为什么?

[英]pthread_cancel() on linux leads to exception/coredump, why?

I was testing the behavior of how pthread_cancel works. 我正在测试pthread_cancel的工作方式。

#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;
}

I expected that 我期望

(1) when cancallation is disabled, any call to pthread_cancel will be ignored but the call shall be remembered (1)禁用cancallation时,对pthread_cancel的任何调用将被忽略,但该调用应被记住

(2) until the cancellation is enabled: it will check if there's previous call to pthread_cancel, and if yes, a cancellation is done. (2)直到启用取消:它将检查是否先前有对pthread_cancel的调用,如果是,则完成取消。

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

But on my linux server, it prints: 但是在我的linux服务器上,它显示:

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

Just having no idea what actuall happened, and how the Fatal exception is throw? 只是不知道发生了什么实际事件,以及如何引发致命异常? I should have some wrong understandings. 我应该有一些错误的理解。 Need your suggestions! 需要您的建议!

Thread cancellation points and C++ do not go well with each other. 线程取消点和C ++不能很好地结合在一起。 Think of what would happen with local variables in the thread stack when the thread is cancelled, will their destructors be called. 想想当取消线程时,线程堆栈中的局部变量会发生什么,将调用它们的析构函数。

Historically, there has been some debate about this, and many pthread implementations chose differently. 历史上,对此有一些争论,许多pthread实现选择了不同的方式。 Some would even implement the cancellation with the same mechanism as a C++ exception, so that the stack will be nicely unwound. 有些甚至甚至可以使用与C ++异常相同的机制来实现取消,以便可以很好地展开堆栈。 But then, a well placed catch will mess things around... 但随后,一个很好地catch会搞乱身边的事物......

But then, pthread_cancel is a POSIX construction, and thus is only well defined for C. 但是, pthread_cancel是POSIX构造,因此仅为C定义良好。

That said, compilers try to do their best. 也就是说,编译器会尽力而为。 In your case, it is probably a bug in your compiler or some library (you don't say what compiler version and what compiler commands you are using...). 就您而言,这可能是您的编译器或某些库中的错误(您没有说正在使用什么编译器版本和使用什么编译器命令...)。 Your code works fine for me (GCC 7.1 and Clang 4.0.1). 您的代码对我来说很好(GCC 7.1和Clang 4.0.1)。

However if I add a try/catch like this, it fail just like yours: 但是,如果我添加这样的try/catch ,它会像您一样失败:

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

If however, I rethrow the exception at the end of the catch it will work fine again: 但是,如果我在catch结束时重新抛出异常,它将再次正常运行:

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

Which proves that in my C++ compiler pthread_cancel uses the same mechanism as C++ exceptions. 这证明在我的C ++编译器中, pthread_cancel使用与C ++异常相同的机制。 My guess is that when the thread is cancelled in C++ mode, it throws an internal exception, and it expects to catch it at the parent of the thread function. 我的猜测是,当线程在C ++模式下被取消时,它将引发内部异常,并且希望将其捕获到线程函数的父级。 But if you return normally from a thread function, when that thread has been cancelled, then this message is shown. 但是,如果您通常从线程函数返回,则在该线程被取消后,将显示此消息。

And since you are not doing anything of this, there are several explanations: 并且由于您没有执行任何操作,因此有几种解释:

  • You are using a compiler that does not support C++ and pthread cancellation. 您使用的编译器不支持C ++和pthread取消。
  • A bug in your version of the compiler/library. 您的编译器/库版本中的错误。
  • You are mixing different versions of the compiler/library. 您正在混合使用不同版本的编译器/库。 Or maybe you are mixing C and C++ libraries. 也许您正在混合使用C和C ++库。

PS 1: I checked adding a local variable with a non trivial destructor to the thread function, and I confirm that the destructor is called when the thread finishes. PS 1:我检查了将具有非琐碎析构函数的局部变量添加到线程函数中,并确认在线程完成时调用了析构函数。

PS 2: I checked calling pthread_exit() from the thread function, without cancellations, and the local destructors are also called. PS 2:我检查了从线程函数调用pthread_exit()的情况,没有取消,并且还调用了本地析构函数。 If I do the try/catch(...) around pthread_exit() it fails with the same FATAL: exception not rethrown . 如果我在pthread_exit()周围进行try/catch(...) ,它将失败并显示相同的FATAL: exception not rethrown So pthread_exit() and pthread_cancel() use the same underlying mechanism. 因此, pthread_exit()pthread_cancel()使用相同的基础机制。

PS 3: All that looks very nice, but thread cancellation can still occur at any point: if the thread cancellation happens in the middle of a cout.operator<<() then any further writing to that stream (from the local destructors for example) will not work at all. PS 3:一切看起来都很不错,但是线程取消仍然可以在任何时候发生:如果线程取消发生在cout.operator<<()的中间,那么任何进一步写入该流的操作(例如,从本地析构函数进行的操作) )根本无法使用。

It is working fine on my PC running Linux. 在运行Linux的PC上运行正常。

$ g++ try.cc -o try -lpthread
$ ./try
sleep 1
sleep 1
cancel thread
sleep 1
sleep 1
sleep 1
sleep 1
$ 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM