C++ condition variable中notify_all()如何保证数据同步

先上代码:

// condition_variable example
#include <iostream>           // std::cout
#include <thread>             // std::thread
#include <mutex>              // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
#include <vector>
#include <chrono>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
std::vector<int> vec;

void print_id(int id) {
	std::unique_lock<std::mutex> lck(mtx);
    cv.wait(lck,[]{return ready;});
	std::cout << "thread " << id << '\n';
    for(int i = 0; i < 1000; ++i){
        std::this_thread::sleep_for(std::chrono::microseconds(10));
        vec.push_back(id+i);
    }
}

void go() {
	std::unique_lock<std::mutex> lck(mtx);
	ready = true;
	cv.notify_all(); // 这是重点
}

int main()
{
	std::thread threads[10];
	// spawn 10 threads:
	for (int i = 0; i < 10; ++i)
		threads[i] = std::thread(print_id, i*1000);
	std::cout << "10 threads ready to race...\n";
    go();
	for (auto& th : threads) {
        th.join();
    }
    std::this_thread::sleep_for(std::chrono::microseconds(2000));
    std::cout<<"vec size: "<<vec.size()<<std::endl;
    
	return 0;
}

我是在网上解释notify_one和notify_all区别的代码(例如:notify_one和notify_all的区别)中添加了vector用来并发插入数据。

notify_one的输出:

@"10 threads ready to race...\r\n"
@"thread 0\r\n"

notify_all的输出:

@"10 threads ready to race...\r\n"
@"thread 6000\r\n"
@"thread 4000\r\n"
@"thread 5000\r\n"
@"thread 0\r\n"
@"thread 3000\r\n"
@"thread 2000\r\n"
@"thread 7000\r\n"
@"thread 1000\r\n"
@"thread 8000\r\n"
@"thread 9000\r\n"
@"vec size: 10000\r\n"

可以看到,在cv notify_all之后,所有的线程都往vecotr中push了数据,这里是如何保证同步的呢,看一下wait的源码:

struct __lock_external
{
    template <class _Lock>
    void operator()(_Lock* __m) {__m->lock();}
};

template <class _Lock>
void
condition_variable_any::wait(_Lock& __lock)
{
    shared_ptr<mutex> __mut = __mut_;
    unique_lock<mutex> __lk(*__mut);
    __lock.unlock();//unlock mutex,进入等待。
    unique_ptr<_Lock, __lock_external> __lxx(&__lock);//__lock_external作为deleter传入到unique_ptr中,析构的时候__lock.lock()
    lock_guard<unique_lock<mutex> > __lx(__lk, adopt_lock);
    __cv_.wait(__lk);
}  // 析构的说话__mut_.unlock(), __lock.lock()

在cv.wait()结束的时候mtx.lock() ,print_id()结束后mtx.unlock(),这个时候10个线程中的vec是保持同步状态。

总结:
1、所有的等待某个cv的线程都必须使用相同的mutex。
2、当wait ()家族函数被调用时,mutex必须被unique_lock锁定。
3、所有通知都会被自动同步化,并发调用notify_one和notify_all没有问题。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
notify_all()是C++11condition_variable类的一个成员函数,用于唤醒所有等待在该condition_variable对象上的线程。当一个线程调用notify_all()时,所有等待在该condition_variable对象上的线程都会被唤醒,但是只有一个线程能够获得锁并继续执行。如果没有线程等待在该condition_variable对象上,则该函数不会有任何作用。 使用notify_all()时需要注意以下几点: 1. 必须先获得与该condition_variable对象关联的unique_lock对象的锁,才能调用notify_all()函数。 2. 在调用notify_all()函数之前,必须先改变条件变量的状态,否则唤醒线程没有意义。 3. 被唤醒的线程需要重新检查条件变量的状态,以确定是否满足继续执行的条件。 下面是一个使用condition_variablenotify_all()的示例代码: ```c++ #include <iostream> #include <thread> #include <mutex> #include <condition_variable> std::mutex mtx; std::condition_variable cv; bool ready = false; void worker_thread() { // 等待主线程通知 std::unique_lock<std::mutex> lock(mtx); while (!ready) { cv.wait(lock); } // 执行任务 std::cout << "Worker thread is running..." << std::endl; } int main() { // 创建工作线程 std::thread worker(worker_thread); // 做一些其他的事情 std::this_thread::sleep_for(std::chrono::seconds(1)); // 通知工作线程开始执行任务 { std::lock_guard<std::mutex> lock(mtx); ready = true; } cv.notify_all(); // 等待工作线程完成 worker.join(); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值