2012-02-14 133 views
3

我想了解如何在C++中使用互斥對象。我有以下的(簡單)多線程我使用的是作爲一個速度測試代碼:互斥對象

struct Rope{ 
    int n, steps, offset; 
    //std::mutex mut; 

    Rope() {} 
    Rope(int n, int steps, int offset) : n(n), steps(steps), offset(offset) {} 

    void compute(){ 
    double a[n]; 
    for (int i=0; i<n; i++) 
     a[i] = i + offset; 
    for (int step=0; step<steps; step++) 
     for (int i=0; i<n; i++) 
    a[i] = sin(a[i]); 
    } 

}; 

void runTest(){ 
    int numRuns = 30; 
    int n = 10000; 
    int steps = 10000; 

    std::vector<Rope> ropes; 
    std::vector<std::thread> threads; 
    for (int i=0; i<numRuns; i++) 
    ropes.push_back(Rope(n, steps, i)); 
    for (auto& r : ropes) 
    threads.push_back(std::thread(&Rope::compute, r)); 
    for (std::thread& t : threads) 
    t.join(); 
}  

的代碼運行正常的是,和看到我的4核機器上的〜4倍的速度提升。當然,我不會在繩子中存儲任何東西,所以不需要互斥體。如果我現在假設我確實有一些我需要保護的數據,我想在該()循環中爲Rope附加一個互斥鎖,並(例如)調用std :: lock_guard。但是,如果我取消對互斥量的註釋,那麼對於賦值和複製操作符,我會遇到一堆關於「使用已刪除函數」的編譯器錯誤。我在安全鎖定對象的目標中缺少什麼?

回答

6

直截了當的方法,使一類線程是在存取方法

class cMyClass { 
    boost::mutex myMutex; 
    cSomeClass A; 
public: 
    cSomeClass getA() { 
    boost::mutex::scoped_lock lock(myMutex); 
    return A; 
    } 
}; 

添加一個互斥鎖屬性並鎖定互斥的問題是,這使得該類不可複製的。這很重要,特別是如果您想要將類的對象存儲在容器中。

我可以通過使互斥鎖成爲靜態的方式來使其工作。

class cMyClass { 
    static boost::mutex myMutex; 
    cSomeClass A; 
public: 
    cSomeClass getA() { 
    boost::mutex::scoped_lock lock(myMutex); 
    return A; 
    } 
}; 

然而,這意味着,當任何其他實例正在訪問類塊的每個實例,因爲他們都有着相同的互斥。

從理論上講,可以通過手動編寫複製構造函數和賦值運算符來使包含非靜態互斥鎖的類成爲可複製的,從而省去互斥鎖。但是,要做到這一點很困難且乏味,特別是對於在開發過程中經常更改的具有大量屬性的類而言。

如果一個靜態互斥鎖阻止對類的所有實例進行阻塞時的訪問是不可接受的,那麼最好和最簡單的方法就是將互斥鎖維持在類之外。以這種方式公開類的內部工作可能看起來不幸,但替代方式更復雜,因此不可靠,並且當訪問類的代碼級別處理互斥鎖時,我經常發現重要的優化。

+0

@MikeSeymour除非我誤解了他在說什麼,否則他需要在所有線程中使用**相同的**互斥體。使用移動語義把它放在容器中是行不通的。 (另一方面,正如目前所寫,每個線程都有自己的'Rope'對象,所以不需要互斥體。當問題沒有被明確解釋時,很難說正確的解決方案。) – 2012-02-14 17:42:43

+0

@ Mike Seymour:'std :: mutex'不可移動。我們可以使'Rope'在每個'Rope'構造函數中默認構造'std :: mutex'來移動或者複製。或者通過讓詹姆斯暗示的互斥體是靜態的。這兩種方法中的哪一種是合適的,只有OP在此時才知道。 – 2012-02-14 20:17:12

+0

我的錯誤;在發佈之前,我應該檢查我的假設。 – 2012-02-15 07:03:13

0

您錯過了mutex不可複製的事實。 代表一個互斥體的副本是什麼意思?獲取和釋放互斥鎖 的地方在Rope::compute中,並且由於所有線程都必須訪問 相同的互斥鎖,因此您必須在runTest中將其定義並通過 引用或通過指針傳入。