2011-07-20 65 views
1

當一個類的單個實例/對象在不同線程之間共享時,我想問一下C++中的線程安全問題(使用帶有C++包裝的POSIX線程)。例如,類A的這個單個對象的成員方法將在不同的線程中被調用。我應該怎樣處理線程安全?多線程中的C++對象

class A { 
    private: 

    int n; 

    public: 

    void increment() 
    { 
     ++n; 
    } 

    void decrement() 
    { 
     --n; 
    } 
}; 
  • 我應該保護類成員n上帶有一個鎖或其他什麼東西遞增/遞減法之內?靜態(類變量)成員是否需要鎖定?
  • 如果一個成員是不可變的,我不必擔心,對吧?
  • 任何我現在無法預見的東西?

除了多線程中的單個對象的情況,多線程的多個對象呢?每個線程都擁有一個類的實例。除了靜態(類變量)成員之外的任何特殊的東西?

這些是我腦海中的事情,但我認爲這是一個很大的話題,如果你有很好的資源並且參考以前的討論,我會很高興。

Regards

回答

-1

您必須保護計數器。沒有其他選擇。

在Windows中可以使用這些功能做到這一點:

#if defined(PLATFORM_WIN32_GNU) 

    typedef long counter_t; 
    inline long _inc(counter_t& v)    { return InterlockedIncrement(&v); } 
    inline long _dec(counter_t& v)    { return InterlockedDecrement(&v); } 
    inline long _set(counter_t &v, long nv)  { return InterlockedExchange(&v, nv); } 

#elif defined(WINDOWS) && !defined(_WIN32_WCE) // lets try to keep things for wince simple as much as we can 

    typedef volatile long counter_t; 
    inline long _inc(counter_t& v)    { return InterlockedIncrement((LPLONG)&v); } 
    inline long _dec(counter_t& v)    { return InterlockedDecrement((LPLONG)&v); } 
    inline long _set(counter_t& v, long nv)  { return InterlockedExchange((LPLONG)&v, nv); } 
0
  • 是的,你應該用一個鎖保護功能,如果他們在多線程環境中使用。你可以使用boost libraries

  • 是的,不可變的成員不應該擔心,因爲這樣的成員一旦被初始化就不能被更改。

關於「多線程多對象」 ..這很大程度上取決於你想做的事,在某些情況下,你可以使用一個thread pool它是有一個定義的線程數站在機制工作進來。但是,那裏沒有thread concurrency,因爲每個線程完成一項工作。

2

這是一個非常大的話題,也許這是不可能完成的話題在這個線程。黃金法則是「當別人正在寫作時,你無法閱讀。」 所以如果你有一個共享一個變量的對象,你必須在訪問共享變量的函數中加入一個鎖。

如果不是這樣,那麼很少有這種情況。 第一種情況是可以使用原子函數的整數,如c-smile所示,在這種情況下,CPU將對緩存使用硬件鎖,因此其他內核無法修改這些變量。 第二種情況是無鎖隊列,它們是使用compare和excange函數確保指令原子性的特殊隊列。

所有其他的情況下,必須鎖定... 第一個aproach是鎖定一切,當涉及更多的對象時,這可能會導致很多問題(ObjA嘗試從ObjB讀取但是,ObjB正在使用變量並且還在等待ObjC等待ObjA)其中,循環鎖定會導致無限期等待(死鎖)。

一個更好的方法是儘量減少線程共享變量的點。 例如,如果你有數據的數組,並且你想並行化數據上的計算,你可以啓動兩個線程,而線程將只在偶數索引上工作,而線程2在奇數上工作。線程正在處理同一組數據,但只要數據不重疊,就不必使用鎖定。 (這稱爲數據並行化)

另一個aproch是將應用程序組織爲一組「工作」(在線程上運行併產生結果的函數),並使工作僅與消息進行通信。你只需要實現一個線程安全的消息系統和一個工作sheduler你完成。或者你可以使用像intel TBB這樣的libray。

這兩種方法都不能解決死鎖問題,但可以讓您將問題隔離起來並更輕鬆地找到錯誤。多線程中的錯誤真的很難調試,有時候也難以找到。因此,如果你正在學習,我建議先從theThread開始,然後開始使用pThread,那麼當你學習基礎移動到更多用戶frendly庫像boost或如果你使用Gcc 4.6作爲編譯器的C + +, + 0x std :: thread