std :: mutex:一次访问多个元素时避免死锁的策略

时间:2016-10-13 09:25:25

标签: c++ multithreading concurrency thread-safety mutex

请考虑以下示例代码:

#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <random>
#include <array>
#include <numeric>


int main()
{
    constexpr std::size_t num_mutices = 3;
    constexpr std::size_t num_entries = 6;
    constexpr std::size_t num_threads = 4;

    std::array<std::mutex, num_mutices> mutices;
    std::array<std::size_t, num_entries> data;

    // fill data with 1, 2, ...
    std::iota(data.begin(), data.end(), 1);

    // setup random generators
    std::random_device rd;
    std::vector<std::mt19937> rand_gens;
    for(std::size_t i = 0; i < num_threads; i++)
        rand_gens.push_back(std::mt19937(rd()));

    std::vector<std::thread> threads;
    for(std::size_t iThread = 0; iThread < num_threads; iThread++)
    {
        threads.emplace_back(std::thread([&data, &mutices, &rand_gens, iThread]()
        {
            // distribution for picking a random value from data
            std::uniform_int_distribution<std::size_t> dist(0,data.size()-1);   

            for(std::size_t a = 0; a < 100; a++)
            {
                auto iFirst = dist(rand_gens[iThread]);
                auto iSecond = dist(rand_gens[iThread]);

                std::unique_lock<std::mutex> lock1(mutices[iFirst % mutices.size()]);
                std::unique_lock<std::mutex> lock2(mutices[iSecond % mutices.size()]);
                std::lock(lock1, lock2);

                std::size_t tmp = data[iFirst];
                data[iFirst] = data[iSecond];
                data[iSecond] = tmp;

                mutices[iFirst % mutices.size()].unlock();
                mutices[iSecond % mutices.size()].unlock();
            }
        }));
    }

    for(std::size_t i = 0; i < num_threads; i++)
        threads[i].join();
}

基本上我有多个线程随机访问矢量元素并交换它们。当然,这只是我想要做的最小工作示例(向双向boost :: graph添加边缘)。

问题是这个程序可能会陷入僵局,我不知道如何解释这个问题。

我认为这可以通过使用层次化的突变来完成。我发现了以下很好的解释:Use Lock Hierarchies to Avoid Deadlock

它声明:

  

规则1:在N级别的互斥锁上持锁时,您可能只在较低级别的互斥锁上获取新锁

因此,我们案例中的水平是所用突变的指数。因此,我应该计算锁定的最小值和最大值以锁定并按顺序获取它们。但是,这仍然会导致死锁,如下所示:

线程1想要锁定互斥锁1和互斥锁3.线程2想要锁定互斥锁2和互斥锁3.现在T1锁定M1,T2锁定M2,现在两者都想获得M3。

我尝试使用try_lock解决这个问题并再次解锁mutice如果线程无法获得所有需要的突变但不知何故我似乎没有得到它:P。

0 个答案:

没有答案