std::condition_variable 条件变量类型

一、成员函数 wait()、 notify_one() 和 notify_all()

      以及 虚假唤醒 的概念

notify_one():任意唤醒一个线程中condition_variable的wait
notify_all():唤醒所有线程中condition_variable的wait

当 m_messages 为空的时候,读取线程中的wait() 函数被唤醒,称为虚假唤醒

// 使用例子
class MyClass{  // 模拟给一个消息队列发消息和处理消息
public:
    void WriteMessage() // 模拟发消息,也就是往消息队列中写
    {
        for (int i = 0; i < 10000; ++i)
        {
            cout << "插入一个元素:" << i << endl;
            std::unique_lock<std::mutex> myLock(m_mutex);
            m_messages.push_back(i);
            m_condition.notify_one();   // 尝试把wait的线程唤醒
        }
    }

    void ReadMessage()   // 模拟处理消息队列中的消息,从中读,也删除
    {
        int command = 0;
        while (true)
        {
            std::unique_lock<std::mutex> myLock(m_mutex);

            // wait() 第二个参数 类型是一个可调用对象
            // 第二个参数返回true,wait()直接返回,程序继续往下执行
            // 第二个参数返回false,wait()将解锁互斥量,并堵塞到本行
            // (意思是返回false时,本线程的代码停在这一行,之前上锁的互斥量也被解锁,
            // 这样不影响其他线程拿到这个互斥量的锁)
            //   直到其他某个线程调用notify_one()成员函数为止、
            // 第二个参数的默认值是false
            // 当其他线程用notify_one()把本wait() 的状态唤醒(原来是阻塞状态)
            // 然后,wait()会不断尝试去拿到这个锁,如果获取不到,程序仍会卡在这里
            // 如果获取到,wait()就继续执行,(第二个参数返回false继续睡眠,
            // 第二个参数返回true,继续往下执行,同时上锁了互斥量)
            // 如果没有第二个参数,则wait()被唤醒之后,直接往下走,
            // 相当于wait()被唤醒之后,第二个参数默认值变成true。
            m_condition.wait(myLock, [this] {  // 第二个参数是一个匿名函数,lambda表达式
//当 m_messages 为空的时候,读取线程中的wait() 函数被唤醒,称为"虚假唤醒"
// 对于"虚假唤醒",wait()的第二个参数(此处为lambda表达式)要正确判断要处理的公共数据是否存在
if (!m_messages.empty()) { return true; } return false; }); // 能执行到这,说明m_messages 中已经有数据了 command = m_messages.front(); m_messages.pop_front(); myLock.unlock(); // unique_lock 可以自己手动解锁 cout << "取出一个元素" << command << endl; } } private: list<int> m_messages; // 模拟消息队列 mutex m_mutex; // 创建一个互斥量成员对象 std::condition_variable m_condition; // 定义一个条件变量对象 }; int main() { MyClass ele; std::thread writeThread(&MyClass::WriteMessage, &ele); // std::thread readThread(&MyClass::ReadMessage, &ele); // readThread.join(); writeThread.join(); cout << "主线程" << endl; system("pause"); return 0; }

notify_one() 与 notify_all() 常用来唤醒阻塞的线程;

notify_one():因为只唤醒等待队列中的第一个线程;不存在锁争用,所以能够立即获得锁;其余的线程不会被唤醒,需要等待再次调用notify_one()或者notify_all();
notify_all():会唤醒所有等待队列中阻塞的线程,存在锁争用,只有一个线程能够获得锁。那其余未获取锁的线程接着会怎么样?会阻塞?还是继续尝试获得锁?答案是会继续尝试获得锁(类似于轮询),而不会再次阻塞。当持有锁的线程释放锁时,这些线程中的一个会获得锁。而其余的会接着尝试获得锁。

 

其他参考链接:https://blog.csdn.net/hltt3838/article/details/119844807

 

posted @ 2020-06-26 13:40  min_zhi  阅读(381)  评论(0编辑  收藏  举报