使用std :: mutex进行死锁模拟

Ama*_*usz 2 c++ mutex stdthread

我有以下示例:

template <typename T>
class container
{
public:
    std::mutex _lock;
    std::set<T> _elements;

    void add(T element)
    {
        _elements.insert(element);
    }

    void remove(T element)
    {
        _elements.erase(element);
    }
};

void exchange(container<int>& cont1, container<int>& cont2, int value)
    {
        cont1._lock.lock();
        std::this_thread::sleep_for(std::chrono::seconds(1));

        cont2._lock.lock();

        cont1.remove(value);
        cont2.add(value);

        cont1._lock.unlock();
        cont2._lock.unlock();
    }

    int main() 
    {
        container<int> cont1, cont2;

        cont1.add(1);
        cont2.add(2);

        std::thread t1(exchange, std::ref(cont1), std::ref(cont2), 1);
        std::thread t2(exchange, std::ref(cont2), std::ref(cont1), 2);

        t1.join();
        t2.join();

        return 0;
    }
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我正在陷入僵局.但是当我使用std :: lock_guard而不是手动锁定和解锁互斥锁时,我没有死锁.为什么?

void exchange(container<int>& cont1, container<int>& cont2, int value)
{
    std::lock_guard<std::mutex>(cont1._lock);
    std::this_thread::sleep_for(std::chrono::seconds(1));

    std::lock_guard<std::mutex>(cont2._lock);

    cont1.remove(value);
    cont2.add(value);
}
Run Code Online (Sandbox Code Playgroud)

Ker*_* SB 7

您的两个代码段无法比较.第二个代码段锁定并立即解锁每个互斥锁,因为临时lock_guard对象在分号处被销毁:

std::lock_guard<std::mutex>(cont1._lock);  // temporary object
Run Code Online (Sandbox Code Playgroud)

使用锁定保护的正确方法是制作它们的范围变量:

{
    std::lock_guard<std::mutex> lock(my_mutex);

    // critical section here

}   // end of critical section, "lock" is destroyed, calling mutex.unlock()
Run Code Online (Sandbox Code Playgroud)

(请注意,还有另一个常见错误,它们相似但不同:

std::mutex mu;
// ...
std::lock_guard(mu);
Run Code Online (Sandbox Code Playgroud)

声明了一个名为mu(就像int(n);)的变量.但是,此代码格式错误,因为std::lock_guard没有默认构造函数.但它会编译,比方说,std::unique_lock它也不会最终锁定任何东西.)

现在解决实际问题:如何以一致的顺序一次锁定多个互斥锁?在整个代码库中,甚至在未来用户的代码库中,甚至在本地案例中,就单个锁定订单达成一致可能是不可行的.在这种情况下,请使用以下std::lock算法:

std::mutex mu1;
std::mutex mu2;

void f()
{
    std::lock(mu1, mu2);

    // order below does not matter
    std::lock_guard<std::mutex> lock1(mu1, std::adopt_lock);        
    std::lock_guard<std::mutex> lock2(mu2, std::adopt_lock);
}
Run Code Online (Sandbox Code Playgroud)

在C++ 17中,有一个新的可变参数锁定保护模板,称为scoped_lock:

void f_17()
{
    std::scoped_lock lock(mu1, mu2);

    // ...
}
Run Code Online (Sandbox Code Playgroud)

构造函数scoped_lock使用相同的算法std::lock,因此两者可以兼容使用.

  • 嗯,我错过了(没读过,只是假设他正确使用了lock_guard). (2认同)