0

我正在尝试实现 unique_lock 的模拟(它只是研究任务,我了解标准库实现完美无缺)。

我已经编写了我需要的所有方法,现在我正在尝试在https://en.cppreference.com/w/cpp/thread/unique_lock/unique_lock的示例上测试我的代码。

当谈到 std::lock(lk_b, lk_c); 无限循环开始。

我做了一些 cout 来了解程序在哪里失去控制,结果如下:锁定 -> 尝试 -> 解锁 -> 锁定 -> 尝试 -> 解锁。

这是部分 unique_lock 实现(我只包括了那些在示例的问题部分中使用的方法)。

template<typename Mutex>
class my_unique_lock {
    Mutex *lockable;
    bool is_acquired;
public:
    explicit my_unique_lock(Mutex& m): lockable{&m}, is_acquired{true}{
        lockable->lock();
        //std::cout << "constructor my_unique_lock(Mutex& m)" << std::endl;
    }

    my_unique_lock(Mutex& m, std::defer_lock_t t): lockable{&m}, is_acquired{false}{
        std::cout << "constructor my_unique_lock(Mutex& m, std::defer_lock_t t)" << std::endl;
    }

    bool try_lock(){
        std::cout << "try_lock" << std::endl;
        if(lockable == nullptr)
            throw std::system_error();
        is_acquired = mutex()->try_lock();
        return is_acquired;
    }

    void lock(){
        std::cout << "lock" << std::endl;
        if(lockable == nullptr || owns_lock())
            throw std::system_error();
        mutex()->lock();
        is_acquired = true;
    }

    void unlock(){
        //std::cout << "unlock" << std::endl;
        if(lockable == nullptr || !owns_lock())
            throw std::system_error();
        mutex()->unlock();
        is_acquired = false;
        std::cout << "unlocked" << std::endl;
    }

    Mutex *mutex() const noexcept {
        //std::cout << "*mutex()" << std::endl;
        return lockable;
    }

    bool owns_lock() const noexcept {
        //std::cout << "owns_lock()" << std::endl;
        return lockable != nullptr && is_acquired;
    }

    ~my_unique_lock(){
        //std::cout << "destructor" << std::endl;
        if(mutex() != nullptr && owns_lock()){
            mutex()->unlock();
            is_acquired = false;
        }
    }
};

这是一个例子。


void update(std::mutex &m_a, std::mutex &m_b, std::mutex &m_c, int &a, int &b, int &c)
{
    {   
        my_unique_lock<std::mutex> lk(m_a);
        a++;
    }

    { 
        my_unique_lock<std::mutex> lk_b(m_b, std::defer_lock);
        my_unique_lock<std::mutex> lk_c(m_c, std::defer_lock);
        std::lock(lk_b, lk_c);
        b = std::exchange(c, b + c);
    }
}

int main()
{
    std::mutex m_a, m_b, m_c;
    int a, b, c = 1;

    std::vector<std::thread> threads;
    for (unsigned i = 0; i < 1; ++i)
        threads.emplace_back(update, std::ref(m_a), std::ref(m_b), std::ref(m_b), std::ref(a), std::ref(b), std::ref(c));

    for (auto& i: threads)
        i.join();

    std::cout << a << "'th and " << a+1 << "'th Fibonacci numbers: "
              << b << " and " << c << '\n';
}

所以,正如我所说,我真的不明白为什么 lock() 会通过这样的调用链(lock -> try_lock -> unlocked)导致无限循环。

4

1 回答 1

5

更改std::ref(m_b), std::ref(m_b)std::ref(m_b), std::ref(m_c)。复制/粘贴错字。

std::lock正在尝试锁定m_b两次。

其他问题:你违反了 0/3/5 的规则。对于锁定/解锁代码(重构),您有多个不同的近乎相同的锁定摆弄。

于 2019-05-22T21:16:17.797 回答