Linux上的PTHREAD_CANCEL()导致异常/Coredump,为什么

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

本文关键字:异常 Coredump 为什么 PTHREAD 上的 CANCEL Linux      更新时间:2023-10-16

我正在测试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;
}

我期望

(1(何时禁用取消呼叫,任何对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)

不知道发生了什么事,以及致命的例外情况如何?我应该有一些错误的理解。需要您的建议!

线程取消点,C 彼此之间的状态不佳。想想线程堆栈中局部变量会发生什么,当线程被取消时,它们的破坏者是否被称为

从历史上看,关于此的辩论已经存在一些辩论,许多Pthread实现的选择不同。有些人甚至会以与C 异常相同的机制实施取消,以便堆栈可以很好地解开。但是,一个放置良好的catch会弄乱问题...

但是,pthread_cancel是一种POSIX结构,因此仅适用于c。

也就是说,编译器会尽力而为。就您而言,这可能是编译器或某些库中的错误(您不说什么编译器版本以及您使用的编译器命令...(。您的代码对我有效(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 和Pthread取消的编译器。
  • 您版本的编译器/库中的错误。
  • 您正在混合编译器/库的不同版本。也许您正在混合C和C 库。

ps 1:我检查了在线程函数中添加带有非琐碎破坏者的局部变量,我确认当线程完成时调用了破坏者。

ps 2:我从线程函数中检查了pthread_exit(),无需取消,并且还调用了本地破坏者。如果我围绕pthread_exit()进行try/catch(...),则使用相同的FATAL: exception not rethrown失败。因此,pthread_exit()pthread_cancel()使用相同的基础机制。

ps 3:所有看起来都非常好,但是线程取消仍然可以在任何时候发生:如果线程取消发生在cout.operator<<()的中间例如,本地破坏者(根本不起作用。

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

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