当等待相同的条件变量时,我们可以使用两个不同的互斥锁吗?

yas*_*shC 6 c++ mutex c++17

考虑以下场景:

线程1

mutexLk1_
gcondVar_.wait(mutexLk1);
Run Code Online (Sandbox Code Playgroud)

线程2

mutexLk2_
gcondVar_.wait(mutexLk2);
Run Code Online (Sandbox Code Playgroud)

线程3

condVar_
gcondVar_.notify_all();
Run Code Online (Sandbox Code Playgroud)

我观察到,并notify_all()没有唤醒两个线程,而是只唤醒两个线程中的一个。如果我要替换mutexLk2mutexLk1. 我得到了一个功能代码。

要重现该问题,请考虑以下来自cppref的修改示例

#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>

std::condition_variable cv;
std::mutex cv_m1;
std::mutex cv_m; // This mutex is used for three purposes:
                 // 1) to synchronize accesses to i
                 // 2) to synchronize accesses to std::cerr
                 // 3) for the condition variable cv
int i = 0;

void waits1()
{
    std::unique_lock<std::mutex> lk(cv_m);
    std::cerr << "Waiting... \n";
    cv.wait(lk, []{return i == 1;});
    std::cerr << "...finished waiting. waits1 i == 1\n";
}

void waits()
{
    std::unique_lock<std::mutex> lk(cv_m1);
    std::cerr << "Waiting... \n";
    cv.wait(lk, []{return i == 1;});
    std::cerr << "...finished waiting. i == 1\n";
}

void signals()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::lock_guard<std::mutex> lk(cv_m);
        std::cerr << "Notifying...\n";
    }
    cv.notify_all();

    std::this_thread::sleep_for(std::chrono::seconds(1));

    {
        std::lock_guard<std::mutex> lk(cv_m);
        i = 1;
        std::cerr << "Notifying again...\n";
    }
    cv.notify_all();
}

int main()
{
    std::thread t1(waits), t2(waits1), t3(waits), t4(signals);
    t1.join();
    t2.join();
    t3.join();
    t4.join();
}
Run Code Online (Sandbox Code Playgroud)

编译命令

g++ --std=c++17 t.cpp -lpthread

这里有趣的是,上面的代码在带有 g++ 9.3 版本的 centos 7.9 系统上(与该系统上的 g++ 10 的行为相同)但在 ubuntu 18.04 系统(带有 g++)上卡在任一等待上(有时 waits1 运行有时等待) 9.4)这可以正常工作,没有任何问题

知道要遵循的预期行为或理想实践是什么吗?因为在我的使用案例中,我需要两个不同的互斥体来保护不同的数据结构,但触发器来自相同的条件变量。

谢谢

Öö *_*iib 6

看来你违反了标准:

\n
\n

33.5.3 类condition_variable [thread.condition.condvar]

\n

无效等待(unique_lock&lock);

\n

要求:lock.owns_lock() 为 true 并且 lock.mutex() 被调用线程锁定,并且

\n

(9.1) \xe2\x80\x94 没有其他线程正在等待此 condition_variable 对象\nor

\n

(9.2) \xe2\x80\x94 lock.mutex() 为所有并发等待(通过 wait、wait_for 或 wait_until)线程提供的每个锁\参数返回相同的值。

\n
\n

清楚两个线程正在等待,并且 lock.mutex() 不返回相同的值。

\n