2010-09-17 37 views
10

C++編譯器如何在C++中實現線程本地存儲0xC++編譯器如何在C++ 0x中實現線程本地存儲?

我已經在谷歌搜索了這個。但我無法找到任何有關此事的信息。

有沒有人有關於此?

+0

C++標準具有零(或非常少)的實現細節。 – 2010-09-17 15:49:23

+0

現在可以幫助:http://www.akkadia.org/drepper/tls.pdf – 2013-01-18 08:42:54

回答

13

請仔細閱讀Wikipedia entry

線程本地存儲並不是C++特有的東西。有時候會有不同的名稱,比如「TLS」(只是線程本地存儲的縮寫)或「線程專用存儲」(TSS)。

大多數操作系統都提供API來訪問每線程存儲。例如,Windows有一個以「TLS」開頭的bunch of API functions。在底層,Win32爲各種線程數據保留了一個特殊區域,包括用戶線程本地存儲,可通過特定CPU寄存器(x86上的FS)訪問。 Linux通過pthread API提供線程特定的存儲,其名稱如pthread_key_create,這些通常使用類似的技術實現。

操作系統可能根本不提供任何支持。但是,如果操作系統通過API提供了一個獨立於進程的線程ID,那麼C++運行時庫可以在內部維護一些概念上的內容,如std::map<thread_id, per_thread_storage>。當然,那麼per_thread_storage是什麼問題。如果一個程序是靜態鏈接的,它可能就像是一個指向一個大型結構的指針,所有的線程局部存儲變量都在程序中聲明爲元素。這是一個過分簡單化,但你得到的一般想法。

訪問線程本地存儲變量顯然不僅僅是一個直接的內存讀取或寫入。這可能比這更有意義。如果你打算在一個特定的函數中使用線程本地/特定存儲,我建議你先將線程本地存儲指針複製到一個局部變量中。

+2

您已經回答了應用程序開發人員如何實現TLS,但沒有回答編譯器和加載程序如何處理C++ 0x thread_local關鍵字 – doron 2010-09-17 11:18:57

+6

@ doron:編譯器和加載器使用操作系統提供的API,或者它們自己做一些與map技術等效的東西,而不需要編程任何代碼。 – Doug 2010-09-17 11:23:02

4

全局變量(或可寫靜態數據 - WSD)通常存儲在獨立於堆棧,堆和代碼的內存塊中。在可執行文件的代碼開始運行之前,會創建並初始化WSD塊。

C++ 0x引入了thread_local關鍵字,它確保每個線程創建一個單獨的全局變量實例。問題是每個線程需要加載一個不同的塊。

下一個難點是變量的地址在鏈接時不固定,並且對於每個線程都不相同。

圍繞此問題有兩種方法。一種是讓編譯器生成一個函數調用以獲得正確的塊,而另一種是更改ABI以將TLS塊存儲在其中一個處理器寄存器中。然後可以使用偏移來訪問正確的thread_local變量。

這與操作系統存儲單個void*值的庫支持不同,該值可用於存儲指向已在進程堆上分配的線程本地塊的指針。

如果你想血淋淋的細節看here

0

您可以使用boost::thread在不同平臺上可移植地處理TLS。每個代碼的實現都在代碼中,並且可以幫助您瞭解不同的系統如何處理這個區域。

+1

在C++ 0x中,編譯器確實支持使用thread_local關鍵字的TLS – doron 2010-09-17 11:22:36

+0

使用boost很好,但是爲了記錄,一些編譯器確實已經購買了問題空間。 http://gcc.gnu.org/onlinedocs/gcc-3.3.1/gcc/Thread-Local.html – 2010-09-17 11:23:33

+0

你說得對,我會更新它。 – 2010-09-17 11:32:29