2017-06-27 58 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 
$ 
相關問題