2013-10-24 50 views
0

我想模擬非靜態成員線程局部變量,像這樣:模擬線程局部變量

template< typename T, unsigned int tNumThread > 
class ThreadLocal 
{ 
private: 

protected: 
    T mData[tNumThread]; 

    unsigned int _getThreadIndex() 
    { 
     return ...; // i have a threadpool and each thread has an index from 0 to n 
    } 

public: 
    ThreadLocal() {}; 
    ~ThreadLocal() {}; 

    T& operator ->() 
    { 
     return mData[_getThreadIndex()]; 
    } 
    ... 
}; 

但問題是線程的這一數字將在運行時確定,我必須從堆中分配mData

我想知道有沒有辦法不使用從堆分配和使用像上面的常規數組?

+1

編譯器通常會提供擴展語法來執行此操作。您需要提及您的編譯器名稱和版本。 –

+0

@HansPassant如果我沒有在VS中記錯,我們有'_declspec(thread)'和C++ 11'threadlocal',但是它們在'Static'變量上工作,並且我想'ThreadLocals'用於'non-static'變量 – MRB

+0

使用這種模式'T mData [tNumThread];'如果sizeof(T)<64或128.否則會造成MESI協議造成的巨大瓶頸。 –

回答

1

每個線程都有自己的堆棧,並且當函數返回時,記得堆棧框架被彈出(或者可以被認爲是彈出)。

這就是爲什麼我們有「無堆疊蟒」,因爲1組(什麼蟒蛇的需求)和多線程不會玩好(見全局解釋器鎖)

你可以把它放在主,這將持續,但是記住C(++)想知道所有在編譯時的大小,所以如果線程數發生變化(在編譯時不固定),那麼就沒有辦法知道這一點。

你真正想要的東西不是主要的東西,但這不會是一個模板(在數字中),因爲在編譯時無法知道該數字。

有一個GCC提供的堆棧分配函數(像malloc),但我找不到它,儘管避免使用它是很好的,因爲然後優化實際上工作。

同樣不要低估你的CPU預讀能力和GCC優化,把數組放在堆上也不錯。

具有良好的照片,但不幸的是只有遠親話題有趣的閱讀: http://www.nongnu.org/avr-libc/user-manual/malloc.html

+0

同意最後一段,但如果我想在數據結構的節點(例如在鏈表中)使用這個類,我有兩個分配給每個節點。所以沒有辦法避免在堆中分配:( – MRB

+0

@MohammadRB所以呢?如果每個線程都有自己的實例,那也不是線程本地的。我忘了名字,但現在我明白了這個問題。新功能對於一次性分配的大量分配很有用(如果您的對象不斷被刪除並重新創建,您可能需要一個池),相信新的優化器,它們是先進的,可用於生產質量的例程。 –

+0

@MohammadRB爲什麼我沒有打勾?你有沒有想過使用C++ 11s thread_local?或者不是將所有副本放在一起,可以在每個線程中創建一個副本,並將其添加到「註冊表」 –

0

我建議:

std::unordered_map<std::thread::id, T, stackalloc> myTLS; 

要麼你gobally鎖定周圍所有的訪問,或者你提前進入準備人口它只能在稍後閱讀。

您可以將它與堆棧分配器結合使用。

typedef short_alloc<pair<const thread::id, T>, maxthrds> stackalloc; 

https://howardhinnant.github.io/stack_alloc.html

如果你想另一種解決方案,在這裏你可以這樣做:

struct Padder 
{ 
    T t; 
    char space_[128 - sizeof(T)]; // if sizeof(T) >= 128 just don't include the padding. 
}; 

std::array<Padder, maxthreads> myTLS; 

對於MESI無瓶頸的訪問。
用這種方法,你必須關心用這個數組中的索引跟蹤你自己的索引。