为什么修改条件变量的条件需要拥有互斥体?

问题描述 投票:0回答:1

考虑这种情况(这是cppreferences中的标准用法):

std::atomic<bool> condition(false);

thread 1:
lock
// check condition the last time before waiting
if (condition == true) { unlock; return; }
// to be clear, I expand "wait" here
{
    // In my understanding
    post task to waiting list
    unlock
    yield
    lock
    check condition
    ...
}

thread 2:
lock
condition=true
notify_one
unlock

我知道线程2需要

lock
unlock
,这样在检查条件之后但在将任务发布到等待列表之前,
notify_one
不会被调用(在我的理解中,如果任务没有执行,
notify_one
不会执行任何操作)已发布到等候名单)。

但是,我认为修改条件(示例中的

condition=true
)不需要拥有互斥锁,也就是说,我认为这也应该有效:

thread 2:
condition=true
lock
notify_one
unlock

因为在我的理解中,如果在线程1锁定之前调用

notify_one
,那么wait之前的条件检查将返回true,线程1根本不会等待。如果在线程 1 解锁后调用
notify_one
,则任务已被发布到等待列表中,因此线程 1 可以唤醒并检查条件,该条件已经为 true。

但是,cppreferences表示即使共享变量是原子的,也必须在拥有互斥锁的同时对其进行修改。有什么我想念的吗?

相关:

为什么 pthread 的条件变量函数需要互斥锁?

为什么条件变量需要锁(因此也需要互斥体)

但是我的问题比他们更具体。


更新:我尝试测试我在不拥有互斥锁的情况下修改条件的想法,到目前为止效果很好:

#include <iostream>
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <thread>

std::mutex mu;
std::atomic<bool> condition(false);
std::condition_variable cv;

void thread_1() {
    std::unique_lock<std::mutex> lock(mu);
    if (condition.load() == true)
        return;
    cv.wait(lock);
}
void thread_2() {
    condition.store(true);
    std::unique_lock<std::mutex> lock(mu);
    cv.notify_one();
}

int main() {
    for (size_t i = 0; i < 100000; ++i) {
        std::thread t1(thread_1);
        std::thread t2(thread_2);
        t1.join();
        t2.join();
    }

    return 0;
}
c++ multithreading locking conditional-variable
1个回答
0
投票

典型用法如下:

std::deque<int> shared_data;
bool consumer_waiting = false;
condition_variable cond;
mutex mut;


void produce(int data) {
    bool consumer_was_waiting;
    {
        scoped_lock lock(mutex);
        consumer_was_waiting = consumer_waiting;
        if (consumer_was_waiting)
            consumer_waiting = false;
        shared_data.push_back(data);
    }
    if (consumer_was_waiting)
        cond.notify_one(); // this call is outside the mutex scope
}

int consume() {
    scoped_lock lock(mutex);
    while (shared_data.empty()) {
        consumer_waiting = true;
        cond.wait(lock);
    }
    return shared_data.pop_front();
}
© www.soinside.com 2019 - 2024. All rights reserved.