2014-09-04 123 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