互斥保护std :: condition_variable [英] Mutex protecting std::condition_variable

查看:118
本文介绍了互斥保护std :: condition_variable的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

即使共享变量是原子变量,也必须在 互斥体以便正确发布对等待的修改 线.任何打算在std :: condition_variable上等待的线程都有 在使用的同一个互斥锁上获取std :: unique_lock 保护共享变量

Even if the shared variable is atomic, it must be modified under the mutex in order to correctly publish the modification to the waiting thread. Any thread that intends to wait on std::condition_variable has to acquire a std::unique_lock, on the same mutex as used to protect the shared variable

http://en.cppreference.com/w/cpp/thread/condition_variable

我了解到,通过使用互斥量保护std :: condition_variable,可以保护我们避免在等待线程实际上没有等待的情况下丢失通知.已经在这里回答: 共享原子变量是如果未在互斥下进行修改,则发布不正确

I understand that by protecting the std::condition_variable with a mutex we are protected against missing a notify if the waiting thread is not actually waiting. Answered here already: Shared atomic variable is not properly published if it is not modified under mutex

我想知道的是,是否有可能仅使用互斥锁来保护std :: condition_variable以及对共享数据进行某种形式的保护? 如果我们修改其他答案中给出的示例,这行得通吗?

What I would like to know is if it's possible to use the mutex only to protect the std::condition_variable, and some other form of protection for the shared data? If we modify the example given in the other answer, would this work?

std::atomic_bool proceed(false);
std::mutex m;
std::condition_variable cv;

std::thread t([&m,&cv,&proceed]()
{
    {
        std::unique_lock<std::mutex> l(m);
        while(!proceed) {
            hardWork();
            cv.wait(l);
        }
    }
});

proceed = true;

{
    std::lock_guard<std::mutex> lock(m);
}
cv.notify_one();
t.join();

还是我错过的内存排序或高速缓存发生了什么事?

Or is there something going on with memory ordering or caches that I have missed?

更新

我知道互斥体通常也可以保护共享数据,使用原子变量只是一个例子.问题不在于如何保护共享数据,而在于是否有必要使用相同的互斥锁来保护两者.使用第二个互斥锁的另一个示例:

I'm aware that the mutex is normally protecting the shared data as well, using the atomic variable was just an example. The question is not about how to protect the shared data, but if it's necessary to use the same mutex to protect both. Another example using a second mutex:

bool proceed(false);
std::mutex boolMutex;

std::mutex cvMutex;
std::condition_variable cv;
std::unique_lock<std::mutex> l(cvMutex);

void setBool()
{
    std::lock_guard<std::mutex> lock(boolMutex);
    proceed = true;
}

bool checkBool()
{
    std::lock_guard<std::mutex> lock(boolMutex);
    return proceed;
}

void worker()
{
    while (true)
    {
        cv.wait(l);
        if (checkBool()) {
            // Do work
            return;
        }
    }
}

int main()
{
    std::thread t(worker);
    setBool();

    {
        std::lock_guard<std::mutex> lock(cvMutex);
    }
    cv.notify_one();
    t.join();

    return 0;
}

推荐答案

我认为Sam的答案不正确.考虑以下代码:

I don't think Sam`s answer is correct. Consider the following code:

// thread #1:
std::unique_lock<std::mutex> l(m);
while (!proceed) cv.wait(l);

// thread #2:
proceed = true; // atomic to avoid data race
cv.notify_one();

这里的问题是以下可能的事件顺序:

The problem here is the following possible sequence of events:

thread #1: while (!proceed) // evaluated as true
thread #2: proceed = true;
thread #2: cv.notify_one();
thread #1: cv.wait(l); // never gets notified

为避免这种情况,典型解决方案是使用相同的互斥锁保护对proceed的修改:

To avoid this scenario, a typical solution is to protect modification of proceed with the same mutex:

// thread #1:
std::unique_lock<std::mutex> l(m);
while (!proceed) cv.wait(l);

// thread #2:
{
   std::lock_guard<std::mutex> l(m);
   proceed = true; // does not need to be atomic
}
cv.notify_one();

现在,proceed = true;必须在while (!proceed)之前或cv.wait(l);开始等待之后发生;都可以.在第一种情况下,根本没有等待.在第二种情况下,保证cv.notify_one();仅在cv.wait(l);实际上正在等待时发生.

Now, proceed = true; must happen either before while (!proceed) or after cv.wait(l); starts waiting; both is ok. In the first case, there is no waiting at all; in the second case, cv.notify_one(); is guaranteed to happen only when cv.wait(l); is actually waiting.

现在,您的(学术类)案件怎么样?

Now, what about your (kind-of academic) case?

// thread #1:
std::unique_lock<std::mutex> l(m);
while (!proceed) cv.wait(l);

// thread #2:
proceed = true; // atomic to avoid data race
{
   std::lock_guard<std::mutex> lock(m);
}
cv.notify_one();

我相信这种情况也是完全正确的,因为上述错误情况也不会发生.出于简单的原因.如果while (!proceed)被评估为false,则不再等待.并且,如果将while (!proceed)评估为true,则在调用cw.wait(l);之前,不会发生通知 .

I believe this case is also perfectly valid, since the above-described wrong scenario cannot happen as well. For simple reason. If while (!proceed) is evaluated as false, again, there is no waiting. And, if while (!proceed) is evaluated as true, then notification cannot happen until cw.wait(l); is invoked.

结论

我相信您的第一个示例还可以,并且cppreference中的引用不正确.

I believe your first example is ok and the quote from cppreference is incorrect.

这篇关于互斥保护std :: condition_variable的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆