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
    评论
### 回答1: notify_one() 是 condition_variable 类的一个成员函数,它的作用是唤醒一个正在等待 condition_variable 的线程,使其获得锁并继续执行。它只会唤醒一个等待的线程,所以如果有多个线程在等待,那么只有一个线程会被唤醒,其他线程还是处于等待状态。使用 notify_one() 的方法是:在线程使用 std::unique_lock 对象来锁定 condition_variable,然后调用 condition_variable 的 wait() 方法来等待,当线程需要唤醒其他线程时,调用 notify_one() 来唤醒等待的线程。 ### 回答2: condition_variablenotify_one()函数是C++标准库用于通知等待在特定条件的线程的函数。当某个线程处于wait状态且在condition_variable上等待时,调用notify_one()函数可以唤醒其的一个线程,使其继续执行。 notify_one()函数的用法较为简单,只需在需要唤醒线程的地方调用该函数即可。当有线程调用condition_variable的wait()函数等待时,其他线程可以通过调用notify_one()函数来唤醒其一个等待的线程。 需要注意的是,notify_one()函数并不会立即唤醒等待的线程,而是将其加入到就绪队列,等待系统调度。因此不能确定哪个线程会被唤醒,也不能保证唤醒的顺序。如果需要唤醒多个线程,可以使用condition_variablenotify_all()函数。 notify_one()函数通常与unique_lock结合使用。在调用notify_one()之前,需要先获得与condition_variable关联的互斥锁,并在互斥锁的作用域内进行唤醒操作,以确保线程安全。 总的来说,condition_variablenotify_one()函数是一种线程同步的机制,通过唤醒等待的线程来实现线程之间的协作。可以用于多线程之间的通信,提高程序的灵活性和效率。 ### 回答3: condition_variable notify_one() 是一个函数,用于通知等待在条件变量上的线程的一个线程醒来。如果没有正在等待的线程,该函数不会做任何操作。该函数在多线程编程被用于线程间的同步与协调。 通常情况下,notify_one() 函数应该和 unique_lock 结合使用。 unique_lock 是一个互斥锁的包装类,它提供了更灵活的锁定和解锁操作,可以在需要的时候进行线程阻塞或者唤醒操作。 notify_one() 的用法如下: 1. 创建一个条件变量对象和一个互斥锁对象。 2. 创建线程函数,并在该函数内部获取互斥锁。在获取锁之前,线程会等待条件变量上的 notify_one() 函数的通知。 3. 创建主线程,并在主线程内部调用 notify_one(),来通知等待在条件变量上的线程的一个线程醒来。 4. 主线程调用 join() 函数,等待所有线程执行完毕。 5. 主线程释放互斥锁。 下面是一个简单的示例代码: ```cpp #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); std::cout << "Worker thread is waiting..." << std::endl; cv.wait(lock, [] { return ready; }); std::cout << "Worker thread is awakened." << std::endl; } int main() { std::thread worker(worker_thread); std::this_thread::sleep_for(std::chrono::seconds(2)); { std::lock_guard<std::mutex> lock(mtx); std::cout << "Main thread notifying worker thread." << std::endl; ready = true; } cv.notify_one(); worker.join(); return 0; } ``` 在这个示例,工作线程等待条件变量 ready 为 true,如果为 false,它会被阻塞在 cv.wait() 。主线程等待2秒后,设置 ready 为 true,并调用 cv.notify_one() 来通知等待的工作线程醒来。工作线程被唤醒后,输出相应的信息。 通过使用 condition_variablenotify_one(),我们可以实现线程间的有效协调和同步,使得在某个条件满足时,线程能够及时醒来执行相应的任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值