2014-02-13 19 views
5

有什麼辦法從Linux的信號處理程序中獲取當前線程ID? getpid()方法做我想要的,但不清楚它是否是異步安全的。 man 7 signal提供了一個異步安全的POSIX方法列表,但是這不會告訴我們有關非POSIX方法(如getpid())的任何內容。據推測,Linux添加的許多非POSIX方法中有一些是異步安全的,但我找不到列表。是否有一種異步安全的方式在Linux中獲取當前線程ID?

還有this answer它聲稱所有直接(不復用)系統調用是異步安全的,但沒有提供證據。

目標是建立某種異步安全的線程本地存儲,因爲__threadis not safe在一般情況下。

它不一定是「Linux線程ID」 - 任何一致的線程ID都可以。例如pthread_self會很好,但沒有任何聲稱是異步安全的。如果我們檢查的glibc的Linux該方法的實現,它推遲到THREAD_SELF宏,它看起來像:

# define THREAD_SELF \ 
({ struct pthread *__self;             \ 
    asm ("movl %%gs:%c1,%0" : "=r" (__self)         \ 
      : "i" (offsetof (struct pthread, header.self)));     \ 
    __self;}) 

似乎是,這應該是異步安全的,如果有問題的線程根據一個制度來填充resgister(也許Linux中的所有線程都是,我不確定)。不過看着that header讓我有點害怕......

+0

您不會使用'pthread_self'作爲線程ID嗎? –

+0

這也可以,但沒有跡象表明這種方法是異步安全的,pthreads方法在一般情況下是異步安全的(當然,互斥方法不是)。 也許我可以使用'pthread_self'的平臺特定實現來破解我知道的線程安全方法的顯式版本? – BeeOnRope

+0

內聯asm片段肯定是異步安全的。如果在執行時收到另一個信號,會發生什麼樣的惡行?沒有。 (注意'getpid'實際上並不是系統調用的方式 - glibc只在第一次嘗試時執行「系統調用」,並在此後緩存該值,而實際中的「系統調用」會進入vDSO)。 – Damon

回答

1

正如Async-signal-safe access to __thread variables from dlopen()ed libraries?您提供提到的(重點是我的):

的__thread變量通常適合票據(至少在Linux/x86平臺), 當變量位於主可執行文件或直接鏈接的DSO中時。

但是,當DSO被dlopen()的ED(和不使用初始EXEC TLS模型), 從給定線程TLS變量的第一個訪問觸發器 的malloc通話...

換句話說,它只需要一次訪問該線程特定變量就可以使其生效並使其在信號處理程序中可用。例如:

  1. 在創建子線程之前阻塞您在父線程中感興趣的信號。
  2. 呼叫pthread_create後,在父線程中解除阻止這些有趣的信號。
  3. 在子線程中初始化您的__thread變量並取消阻止這些有趣的信號。

我通常將unix管道的寫入結束存儲在該特定於胎面的變量中,並且信號處理程序將信號編號寫入該管道。管道的讀端在select/epoll的同一線程中註冊,這樣我就可以處理信號環境以外的信號。例如:

__thread int signal_pipe; // initialized at thread start 

extern "C" void signal_handler(int signo, siginfo_t*, void*) 
{ 
    unsigned char signo_byte = static_cast<unsigned>(signo); // truncate 
    ::write(signal_pipe, &signo_byte, 1); // standard unix self pipe trick 
} 
+0

不幸的是,這種解決方案在我的場景(庫)中是不可能的,因爲我沒有創建線程的鉤子,所以我不能執行你描述的手。 – BeeOnRope

+0

@BeeOnRope我明白了。 [你總是可以掛鉤圖書館電話](http://www.opensourceforu.com/2011/08/lets-hook-a-library-function/)。你可以鉤入'pthread_create' ... –

相關問題