2014-09-04 15 views
4

我有一個C++ 11線程死鎖。這是通過使用具有多個線程池的兩個獨立函數來實現的。爲了避免這種僵局,這個例子如何解決?我認爲解決方案與鎖定程序的一致排序有關。如何修復一個C++線程死鎖的例子

#include <thread> 
#include <mutex> 
#include <iostream> 

std::mutex kettle; 
std::mutex tap; 

#define THREAD_POOL 8 

void kettle_tap(){ 

    std::cout << "Locking kettle in " << std::this_thread::get_id() << std::endl; 
    // Lock the mutex kettle by creating and using lock_guard kettle_lock. 
    std::lock_guard<std::mutex> kettle_lock(kettle); 
    std::cout << "Locked kettle in " << std::this_thread::get_id() << std::endl; 

    std::cout << "Locking tap in " << std::this_thread::get_id() << std::endl; 
    // Lock the mutex tap by creating and using lock_guard tap_lock. 
    std::lock_guard<std::mutex> tap_lock(tap); 
    std::cout << "Locked tap in " << std::this_thread::get_id() << std::endl; 

    std::cout << "Filling kettle in " << std::this_thread::get_id() << std::endl; 
} 

void tap_kettle(){ 

    std::cout << "Locking tap in " << std::this_thread::get_id() << std::endl; 
    // Lock the mutex tap by creating and using lock_guard tap_lock. 
    std::lock_guard<std::mutex> tap_lock(tap); 
    std::cout << "Locked tap in " << std::this_thread::get_id() << std::endl; 

    std::cout << "Locking kettle in " << std::this_thread::get_id() << std::endl; 
    // Lock the mutex kettle by creating and using lock_guard kettle_lock. 
    std::lock_guard<std::mutex> kettle_lock(kettle); 
    std::cout << "Locked kettle in " << std::this_thread::get_id() << std::endl; 

    std::cout << "Filling kettle in " << std::this_thread::get_id() << std::endl; 

} 

int main(){ 

    std::thread pool[THREAD_POOL]; 

    for (int t = 0; t < THREAD_POOL; t += 2){ 
     pool[t] = std::thread(kettle_tap); 
     pool[t+1] = std::thread(tap_kettle); 
    } 

    for (int t = 0; t < THREAD_POOL; ++t){ 
     pool[t].join(); 
    } 

    std::cout << "Threads are all joined" << std::endl; 

    return 0; 

} 

回答

6

std::lock(Mutexes...)

在你的情況下,兩個kettle_tap()tap_kettle()應該開始:

std::lock(tap, kettle); 

但互斥參數的順序並不重要,所以可以跨兩種功能不同

鎖定多個互斥鎖

鎖作爲參數傳遞的所有對象,如果有必要阻塞調用線程。

該函數使用對其成員的未指定序列的調用來鎖定對象lock,try_lock和unlock,確保返回時鎖定所有參數(不會產生任何死鎖)。

如果函數無法鎖定所有對象(例如因爲其內部調用中的一個引發異常),則該函數首先在失敗之前解鎖成功鎖定的所有對象(如果有的話)。

後來,如果你想鎖的所有權轉讓給std::lock_guard

std::lock(tap, kettle); 
std::lock_guard<std::mutex> kettle_lock(kettle, std::adopt_lock); 
std::lock_guard<std::mutex> tap_lock(tap, std::adopt_lock); 
+1

啊,非常好。感謝您的幫助和所有的細節。鎖定採用技巧很好。 – d3pd 2014-09-04 09:06:09

2

你說得對。通過避免循環等待,死鎖可以是prevented。在您的示例中,爲避免死鎖,請在tap_kettle方法中將kettle_lock移至tap_lock以上。這樣你就可以得到部分訂單。

+0

非常感謝您對幫助。 – d3pd 2014-09-04 09:05:30