2014-07-02 157 views
6

根據pthread_key_create手冊頁,我們可以關聯一個析構函數以在線程關閉時調用。我的問題是我註冊的析構函數沒有被調用。我的代碼的要點如下。pthread_key_create析構函數沒有被調用

static pthread_key_t key; 
static pthread_once_t tls_init_flag = PTHREAD_ONCE_INIT; 

void destructor(void *t) { 
    // thread local data structure clean up code here, which is not getting called 
} 

void create_key() { 
    pthread_key_create(&key, destructor); 
} 

// This will be called from every thread 
void set_thread_specific() { 

    ts = new ts_stack; // Thread local data structure 

    pthread_once(&tls_init_flag, create_key); 
    pthread_setspecific(key, ts); 
} 

任何想法什麼可能會阻止這個析構函數被調用?我也在使用atexit()在主線程中進行一些清理。有沒有機會干擾被調用的析構函數?我也嘗試刪除它。儘管如此,仍然沒有工作。另外我不清楚我是否應該將主線程作爲與atexit分開的情況處理。 (這是由的方式來使用的atexit必須的,因爲我需要做的,在應用程序退出一些專用清理)

回答

0

我寫了一個簡單的測試,我改變了移動set_thread_specific之外create_key調用你的唯一。

也就是說,我在主線程中調用它。

然後我看到我的銷燬在線程例程退出時被調用。

2

這是設計。

主線程退出(通過返回或致電exit()),並且不使用pthread_exit()。 POSIX文件pthread_exit調用線程特定的析構函數。

您可以在main的末尾添加pthread_exit()。或者,您可以使用atexit來銷燬。在這種情況下,將線程特定的值設置爲NULL將會很乾淨,以便在調用pthread_exit的情況下,該銷燬不會發生兩次。

UPDATE其實,我只需添加這對我的全球的單元測試設置功能,解決了我近憂:

::atexit([] { ::pthread_exit(0); }); 

所以,在我的全球夾具類MyConfig的背景:

struct MyConfig { 
    MyConfig() { 
     GOOGLE_PROTOBUF_VERIFY_VERSION; 
     ::atexit([] { ::pthread_exit(0); }); 
    } 
    ~MyConfig() { google::protobuf::ShutdownProtobufLibrary(); } 
}; 

一些使用的參考文獻:


PS。當然,C++ 11 introduced <thread>,所以你有更好和更便攜的原始工作。

+0

添加了一個簡潔的解決方法,我目前無法想到主要缺點:':: atexit([] {:: pthread_exit(0);});' – sehe

+0

請注意POSIX狀態*通過調用註冊的函數to atexit()必須返回以確保所有註冊的函數都被調用*。因此,如果您在atexit註冊函數中使用'pthread_exit()',則可能不會調用atexit堆棧上的其餘任何函數。 –

+0

@亞歷山大·克勞爾很好的一點。當我再次觸摸代碼時,我將不得不重新審視這個想法 – sehe

0

我打電話析構函數()手動在主(結束)

void * ThreadData = NULL; 

if ((ThreadData = pthread_getspecific(key)) != NULL) 
     destructor(ThreadData); 

當然關鍵應妥善早些時候在的main()代碼初始化。 PS。調用了pthread_exit()在年底的main()似乎掛起整個應用程序...

0

你處理主線程的使用atexit獨立的情況下,最初的想法對我來說最好的工作。

確保pthread_exit(0)覆蓋進程的退出值。

#include <pthread.h> 
#include <stdio.h> 
#include <stdlib.h> 

class ts_stack { 
public: 
    ts_stack() { 
    printf ("init\n"); 
    } 
    ~ts_stack() { 
    printf ("done\n"); 
    } 
}; 

static void cleanup (void); 

static pthread_key_t key; 
static pthread_once_t tls_init_flag = PTHREAD_ONCE_INIT; 

void destructor(void *t) { 
    // thread local data structure clean up code here, which is not getting called 
    delete (ts_stack*) t; 
} 

void create_key() { 
    pthread_key_create(&key, destructor); 
    atexit(cleanup); 
} 

// This will be called from every thread 
void set_thread_specific() { 
    ts_stack *ts = new ts_stack(); // Thread local data structure 

    pthread_once(&tls_init_flag, create_key); 
    pthread_setspecific(key, ts); 
} 

static void cleanup (void) { 
    pthread_exit(0); // <-- Calls destructor but sets exit status to zero as a side effect! 
} 

int main (int argc, char *argv[]) { 
    set_thread_specific(); 
    return 3; // Attempt to exit with status of 3 
} 
0

它已經在sehe的回答,只是存在於一個緊湊的方式的關鍵點:

    例如,下面的程序將與即使零main()中有三個數字返回狀態退出
  • pthread_key_create()析構函數調用通過調用pthread_exit()觸發。
  • 如果線程的啓動例程返回,則行爲就好像調用了pthread_exit()(即觸發析構函數調用)。
  • 但是,如果main()返回,行爲就好像調用了exit() - 沒有觸發析構函數調用。

這在http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_create.html中有解釋。另見C++ 17 6.6.1p5或C11 5.1.2.2.3p1。