c++条件变量是否应在锁定状态下通知

anhgbhbe  于 2022-12-20  发布在  其他
关注(0)|答案(4)|浏览(139)

我在www.example.com上找到了条件变量http://en.cppreference.com/w/cpp/thread/condition_variable的以下示例www.cppreference.com。对cv.notify_one()的调用被放置在锁之外。我的问题是,是否应该在持有锁的同时进行调用,以确保等待线程实际上处于等待状态,并将接收通知信号。

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

std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;

void worker_thread()
{
    // Wait until main() sends data
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk, []{return ready;});

    // after the wait, we own the lock.
    std::cout << "Worker thread is processing data\n";
    data += " after processing";

    // Send data back to main()
    processed = true;
    std::cout << "Worker thread signals data processing completed\n";

    // Manual unlocking is done before notifying, to avoid waking up
    // the waiting thread only to block again (see notify_one for details)
    lk.unlock();
    cv.notify_one();
}

int main()
{
    std::thread worker(worker_thread);

    data = "Example data";
    // send data to the worker thread
    {
        std::lock_guard<std::mutex> lk(m);
        ready = true;
        std::cout << "main() signals data ready for processing\n";
    }
    cv.notify_one();

    // wait for the worker
    {
        std::unique_lock<std::mutex> lk(m);
        cv.wait(lk, []{return processed;});
    }
    std::cout << "Back in main(), data = " << data << '\n';

    worker.join();
}

如果notify_one()调用被移动到锁内部以保证等待线程接收到通知信号,

// send data to the worker thread
{
    std::lock_guard<std::mutex> lk(m);
    ready = true;
    cv.notify_one();
    std::cout << "main() signals data ready for processing\n";
}
hvvq6cgz

hvvq6cgz1#

你不需要在锁的情况下通知,但是,由于通知在逻辑上是在实际值被更改时发生的(否则,为什么要通知?),而且更改必须在锁的情况下发生,所以它通常在锁内完成。
不会有实际可观察到的差异。

lyr7nygr

lyr7nygr2#

如果我没理解错你的问题的话,它等同于 “当通知程序线程试图通知其他线程中的某个CV时,是否应该锁定互斥锁”
不,这不是强制性的,甚至会产生一些反作用。
当从另一个线程通知condition_variable时,它试图重新锁定它在其上休眠的互斥体。从其工作线程锁定该互斥体将阻塞试图锁定它的另一个线程,直到该锁 Package 器超出范围。

附言

如果您从发送数据到工作线程的函数中删除锁定,readyprocessed至少应该是原子的。当前它们由锁定同步,但是当您删除锁定时,它们不再是线程安全的

wz1wpwve

wz1wpwve3#

在调用notify_all时保持锁是至关重要的:当condition_variable在等待之后被破坏时,虚假唤醒可导致等待结束,并且condition_variable在notify_all被调用于已被破坏的对象之前被破坏。

5sxhfpxr

5sxhfpxr4#

如果不等待条件变量,则通知将丢失。您是否持有任何锁并不重要。条件变量是同步原语,不需要锁来保护。
锁和不锁都可能丢失信号。互斥锁只保护readyprocessed等普通数据。

相关问题