2014-06-08 42 views
1

Windows NT有一個名爲GetCurrentThreadId的很好的函數,它的名字就意味着它。它的實現非常快,因爲它只是從NT內核創建線程期間從線程本地存儲中讀取一個變量。我想在Linux中實現它,但我遇到了一個問題。在Linux中快速實現「GetCurrentThreadId」

我最初的實現是這樣的:

typedef pid_t ThreadID; 

ThreadID GetCurrentThreadId(void) 
{ 
    static __thread ThreadID t_cachedID = (ThreadID) -1; 

    if (__builtin_expect(t_cachedID == (ThreadID) -1, 0)) 
    { 
     t_cachedID = (ThreadID) syscall(__NR_gettid); 
    } 

    return t_cachedID; 
} 

問題是fork。在使用fork的程序中,t_cachedID變爲陳舊 - 新子進程的主線程具有線程的線程本地存儲的副本,該副本稱爲fork,而t_cachedID不再正確。

該解決方案應該是pthread_atfork,以便將新子進程中的t_cachedID值更改爲-1,但是Pthreads API的規範也是如此,設計不佳。如果你是一個使用dlclose卸載的DLL,pthread_atfork不知道這一點,並且仍然會嘗試在fork和kaboom上調用你的函數。糟糕的設計決定#1。沒有API可以刪除你的回調函數。糟糕的設計決定#2。

有一個模糊記錄的glibc函數,名爲__register_atfork,它似乎設計用於處理此問題,但它需要DLL句柄而不是提供一種方法來刪除您的*_atfork處理程序。在嘗試解決POSIX糟糕的設計決策時,glibc做出的設計決定#1很糟糕。

如何獲取我自己的DLL句柄?在Linux中,似乎dlopen每次有人在DLL/.so文件上調用dlopen時都會返回不同的void *句柄,而不僅僅是維護引用計數...?它不像Windows中的DLL句柄等於節映射的基地址。除非有一些簡單的方法可以在Linux中獲得您自己的DLL句柄,否則這會讓設計決定#2變得糟糕。

有沒有更好的,正確的方法來做到這一點?

+1

因爲你正在使用一個線程局部靜態變量和複印件這,pthreads設計不好?另外,Linux沒有DLL。它具有共享對象,它們在最低級別上往往有很大差異...... – rubenvb

+0

爲什麼不使用'pthread_self()'的結果來唯一標識一個正在運行的線程或'pthread_create()'設置爲新創建的線程的標識符? – alk

+0

rubenvb:它們是庫和動態鏈接的。 API設計糟糕的原因是因爲'pthread_atfork'不能安全地被卸載的代碼使用。如果它不是設計問題,glibc不會創建這個'__register_atfork'函數。同樣的原因是'__cxa_atexit'被創建:'atexit'具有完全相同的問題(即POSIX沒有從歷史中學習)。 alk:由於'pthread_create'的返回值與剛剛創建的線程返回的'pthread_self'的值不匹配,並且存在生存期問題。這不是一個非常有用的標識符。 – Myria

回答

3

嗯,其實POSIX已經contains function返回線程ID:

pthread_self() //thanks to alk 

老答案:

int thr_self() 

+0

'thr_self'似乎是SunOS特有的,似乎並不存在於Linux中。 – Myria

+0

POSIX爲此提供'pthread_self()'。 @Myria – alk

+0

@alk非常感謝!只是瞥了一眼錯誤的代碼分支 – Dewfy