5

我想問一下有關多線程的最簡單的Mutex方法。下面的代碼是線程安全的(quick-n-dirty)嗎?有史以來最簡單的互斥體。這個例子工作嗎?它是線程安全的嗎?

class myclass 
{ 
    bool locked; 
    vector<double> vals; 

    myclass(); 
    void add(double val); 
}; 

void myclass::add(double val) 
{ 
    if(!locked) 
    { 
     this->locked = 1; 
     this->vals.push_back(val); 
     this->locked = 0; 
    } 
    else 
    { 
     this->add(val); 
    } 
} 

int main() 
{ 
    myclass cls; 
    //start parallelism 
    cls.add(static_cast<double>(rand())); 
} 

這種工作?它是線程安全的嗎?我只是想了解如何編寫最簡單的互斥鎖。

如果您對我的示例有任何建議,那就太好了。

謝謝。

謝謝你說它不起作用。你能否提出一個獨立於編譯器的解決方案?

+5

制定正確的互斥機制是一項複雜的業務。我會使用已經存在的東西。 – andre 2013-02-11 18:57:52

+0

通常,互斥體等同步原語需要一些原子性(通常在CPU指令級別)。下面是我發現的一個有趣的鏈接:http://lists.canonical.org/pipermail/kragen-tol/1999-August/000457.html – Tom 2013-02-11 19:06:52

+0

最簡單的互斥體(或一般的同步構造)是你不需要的; - ) – delnan 2013-02-11 19:16:03

回答

8

它是線程安全的?

當然不是。如果一個線程在檢查和設置鎖之間被搶佔,那麼第二個線程可以獲得該鎖;如果控制權然後返回到第一個線程,那麼兩者都會獲得它。 (當然,在現代處理器上,兩個或多個內核可能會同時執行相同的指令以實現更多的鬧劇)。

至少,您需要原子測試和設置操作來實現鎖定喜歡這個。在C++ 11庫提供了這樣一件事:

std::atomic_flag locked; 

if (!locked.test_and_set()) { 
    vals.push_back(val); 
    locked.clear(); 
} else { 
    // I don't know exactly what to do here; 
    // but recursively calling add() is a very bad idea. 
} 

或更好:

std::mutex mutex; 

std::lock_guard<std::mutex> lock(mutex); 
vals.push_back(val); 

如果你有一箇舊的實現,那麼你就必須依靠任何分機/庫可用對你來說,因爲當時語言或標準庫沒有任何幫助。

+0

hmmmmm。感謝您的答案。我使用VS2010和g ++,第一個不支持互斥鎖。任何其他編譯器獨立的想法 – 2013-02-11 19:42:39

+1

@SamerAfach:[Boost.Thread](http://www.boost.org/doc/libs/release/doc/html/thread.html)和[just :: thread](http://www.stdthread .co.uk /)庫具有可移植和(或多或少)直接替換C++ 11互斥體的功能。如果沒有Windows API(關鍵部分或任何他們稱之爲的);顯然這不是獨立於編譯器的,所以你需要一些仔細放置的#define來選擇使用哪一個。 – 2013-02-11 19:48:36

+0

@MikeSymour如果我使用boost Mutex(或任何其他Mutex),是否會使代碼對於其他並行化庫(如OpenMPI和OpemMP)是線程安全的?或者Mutex專門爲從中獲取Mutex的圖書館的並行性而工作? – 2013-02-12 07:46:37

2

工作的呢?它是線程安全的嗎?

號將在次失敗。

你互斥只會工作,如果其他線程從未做到這兩條線的執行之間的任何東西:

if(!locked) 
{ 
    this->locked = 1; 

...你有沒有保證。

要了解如何互斥寫入,請參閱this SO post

2

不,這不是線程安全的。

考慮在更多或更少的同時運行myclass::add兩個線程。另外,假設.locked的值是false

第一線程執行直到幷包括這一行:

if(!locked) 
{ 

現在,假設該系統的上下文切換至所述第二線程。它也執行到同一行。

現在我們有兩個不同的線程,都認爲他們有獨佔訪問,並且無論是如果的!locked條件內。

他們都將調用vals.push_back()在更多或更少的同一時間。

繁榮。

5

不,這不是線程安全的。有

if(!locked) 

this->locked = 1; 

如果這兩個語句之間的上下文切換之間的比賽,你的鎖止機構分崩離析。您需要原子指令test and set,或者只需使用現有的mutex

5

此代碼不提供vals載體的原子修改。考慮以下情形:

//<<< Suppose it's 0 
if(!locked) 
{ //<<< Thread 0 passes the check 
    //<<< Context Switch - and Thread 1 is also there because locked is 0 
    this->locked = 1; 
    //<<< Now it's possible for one thread to be scheduled when another one is in 
    //<<< the middle of modification of the vector 
    this->vals.push_back(val); 
    this->locked = 0; 
} 
1

其他已經顯示出你的互斥量能怎麼失敗的,所以我不會老調重彈自己的觀點。我只會添加一件事:最簡單的互斥體實現比您的代碼複雜得多。

如果你感興趣的細節問題(或者即使你是不是 - 這是東西軟件開發人員應該知道),你應該看看Leslie Lamport's Bakery Algorithm並從那裏走。

相關問題