A little analysis of deadlock

Locking multiple mutex objects
In some cases we may need to lock multiple mutex objects, consider the following code

std::mutex mt1, mt2;
// thread 1
{
    std::lock_guard<std::mutex> lck1(mt1);
    std::lock_guard<std::mutex> lck2(mt2);
    // do something
}
// thread 2
{
    std::lock_guard<std::mutex> lck2(mt2);
    std::lock_guard<std::mutex> lck1(mt1);
    // do something
}

If thread 1 executes to line 5, it happens that thread 2 executes to line 11. Then there will be

Thread 1 holds mt1 and waits for mt2.
Thread 2 holds mt2 and waits for mt1
to deadlock.
In order to avoid this kind of deadlock, for any two mutually exclusive objects, when locking in multiple threads, the sequence should be the same. The previous code should be modified to

std::mutex mt1, mt2;
// thread 1
{
    std::lock_guard<std::mutex> lck1(mt1);
    std::lock_guard<std::mutex> lck2(mt2);
    // do something
}
// thread 2
{
    std::lock_guard<std::mutex> lck1(mt1);
    std::lock_guard<std::mutex> lck2(mt2);
    // do something
}

A better approach is to use the std::lock and std::try_lock functions in the standard library to lock multiple Lockable objects. std::lock (or std::try_lock) will use an algorithm to avoid deadlocks to perform lock operations on multiple objects to be locked (std::try_lock performs try_lock operations), when the objects to be locked are unavailable When an object is used, std::lock will block the current thread until all objects are available (std::try_lock will not block the thread when an object is unavailable, it will release other locked objects and return immediately). Use std::lock to rewrite the previous code, here deliberately make the order of the parameters of the 6th line and the 13th line different

Guess you like

Origin blog.csdn.net/qq_23350817/article/details/108695657