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變得糟糕。
有沒有更好的,正確的方法來做到這一點?
因爲你正在使用一個線程局部靜態變量和複印件這,pthreads設計不好?另外,Linux沒有DLL。它具有共享對象,它們在最低級別上往往有很大差異...... – rubenvb
爲什麼不使用'pthread_self()'的結果來唯一標識一個正在運行的線程或'pthread_create()'設置爲新創建的線程的標識符? – alk
rubenvb:它們是庫和動態鏈接的。 API設計糟糕的原因是因爲'pthread_atfork'不能安全地被卸載的代碼使用。如果它不是設計問題,glibc不會創建這個'__register_atfork'函數。同樣的原因是'__cxa_atexit'被創建:'atexit'具有完全相同的問題(即POSIX沒有從歷史中學習)。 alk:由於'pthread_create'的返回值與剛剛創建的線程返回的'pthread_self'的值不匹配,並且存在生存期問題。這不是一個非常有用的標識符。 – Myria