c++11多线程编程 condition_variable wait notify_one notify_all 第八讲

 

(1)条件变量std::condition_variable、wait() 、notify_one()、notify_all()

wait()用来等一个东西
            1、如果第二个参数返回值是true,那么这一行就继续往下运行。
            2、如果第二个参数返回值是false那么wait将解锁互斥量,并堵塞在这一行
            堵到什么时候呢?堵到其他函数调用notify_one()函数为止。

如果wait没有第二个参数,那么第二个参数返回false效果一样。

 当其他函数使用notify_one将wait唤醒,然后wait就会重新尝试获取锁。如果获取不到,代码就卡在wait这边获取锁,如果获取到锁,就会继续执行。
1)唤醒wait后,并加锁成功接下来:
            如果第二个参数返回值是true,那么这一行就继续往下运行。
            如果第二个参数返回值是false那么wait将解锁互斥量,并堵塞在这一行,等待唤醒
2)如果wait没有第二个参数,只要被唤醒,那么一旦获取到锁,就从wait这边继续向下执行。
(2)上述代码的深入思考
(3) notify_all()
条件变量std::condition_variable wait() notify_one()

class A
{
    public:
    
    //把收到的消息放到一个队列中
    void inMsgRecvQueue()    //unlock()
    {
        for(int i=0;i<10000;++i)
        {
            cout<<"inMsgRecvQueue():"<<i<<endl;       
            std::unique_lock<std::mutex> lguard1(my_mutex1);                            
            msgRecvQueue.push_back(i);//假设这个数字就是收到的命令,把他加入到队列中
            //代码处理。。。
        }
         return ;
    }
    
    bool outMsgProc(int &command)
    {   //双重锁定,双重检查 
        if(!msgRecvQueue.empty())
        {   //添加这个双重锁定是因为每次不管是不是空都加锁然后再释放效率低,这样可以避免每次都加锁
            
            std::unique_lock<std::mutex> lguard1(my_mutex1);     
            if(!msgRecvQueue.empty())
            {
                command = msgRecvQueue.front();//返回第一个元素,但不检查元素是否存在   
                msgRecvQueue.pop_front();//移除第一个元素         
                return true;
            } 
        }    
        return false;        
    }
    //把数据从消息队列中取出线程
    void outMsgRecvQueue()
    {
        int command =0;
        for(int i=0;i<10000;++i)
        {
            bool result=outMsgProc(command);
            if(result==true)
            {
                cout<<"outMsgRecvQueue()执行,取出一个元素"<<command<<endl;
                //对消息处理
            }
            else
            {
                //消息队列为空
                sleep(100);
                cout<<"outMsgRecvQueue()执行,但是消息队列为空"<<i<<endl;
            }
        }
        cout<<"end"<<endl;
    }
    
    private:
    std::list<int> msgRecvQueue;//容器(消息队列)专门用于代表玩家发送的命令
    std::mutex my_mutex1;//创建了一个互斥量
    std::mutex my_mutex2;//创建了一个互斥量
    
    
};

int main()
{   //条件变量std::condition_variable wait() notify_one()
    //线程A:等待一个条件满足
    //线程B:向消息队列中放消息
    
    A myobja;
    std::thread my_out_Thread(&A::outMsgRecvQueue,&myobja);//outMsgRecvQueue为起始函数的线程
    std::thread my_in_Thread(&A::inMsgRecvQueue,&myobja);//inMsgRecvQueue为起始函数的线程    
    outMsgRecvQueue.join();
    inMsgRecvQueue.join();     
    cout<<"主线程收尾,正常退出"<endl;
    return 0;
}

------------------------------------------------

class A
{
    public:
    
    //把收到的消息放到一个队列中
    void inMsgRecvQueue()    //unlock()
    {
        for(int i=0;i<10000;++i)
        {
                   
            std::unique_lock<std::mutex> lguard1(my_mutex1);
            cout<<"inMsgRecvQueue()插入一个元素:"<<i<<endl;                            
            msgRecvQueue.push_back(i);//假设这个数字就是收到的命令,把他加入到队列中
            /*
            my_con.notify_one();//我们尝试把wait()唤醒,这行运行完,那么outMsgRecvQueue中的wait就会被唤醒
            notify_one()通知唤醒一个线程,只能通知一个线程。
            */
            my_con.notify_all();//唤醒所有处于wait状态的线程
            
            //代码处理。。。
        }
        return;
    }
    
    //把数据从消息队列中取出线程
    void outMsgRecvQueue()
    {
        int command =0;
        while(true)
        {
            std::unique_lock<std::mutex> lguard1(my_mutex1);
            
            //wait()用来等一个东西
            //如果第二个参数返回值是true,那么这一行就继续往下运行。
            //如果第二个参数返回值是false那么wait将解锁互斥量,并堵塞在这一行
            //堵到什么时候呢?堵到其他函数调用notify_one()函数为止
            //如果wait没有第二个参数,那么第二个参数返回false效果一样。
            当其他函数使用notify_one将wait唤醒,然后wait就会重新尝试获取锁。
            如果获取不到,代码就卡在wait这边获取锁,如果获取到锁,就会继续执行。
            1)唤醒wait后,并加锁成功接下来:
            如果第二个参数返回值是true,那么这一行就继续往下运行。
            如果第二个参数返回值是false那么wait将解锁互斥量,并堵塞在这一行,等待唤醒
            2)如果wait没有第二个参数,只要被唤醒,那么一旦获取到锁,就从wait这边继续向下执行。
            
            my_con.wait(lguard1,[this]{ //一个lambda表达式,就是一个可调用对象
                if(!msgRecvQueue.empty())
                    return true;
                return false;
            });
            command = msgRecvQueue.front();//返回第一个元素,但不检查元素是否存在   
            msgRecvQueue.pop_front();//移除第一个元素
            cout<<"outMsgRecvQueue取出一个元素"<<std::this_thread::get_id()<<endl;    
            lguard1.unlcok(); //因为unique_lock的灵活性,所以可以随时解锁、免得锁太久
            
        }
        cout<<"end"<<endl;
    }
    
    private:
    std::list<int> msgRecvQueue;//容器(消息队列)专门用于代表玩家发送的命令
    std::mutex my_mutex1;//创建一个互斥量
    std::condition_variable my_con;//创建一个条件变量对象
    
    
};

int main()
{   //条件变量std::condition_variable wait() notify_one()
    //线程A:等待一个条件满足
    //线程B:向消息队列中放消息
    std::condition_variable实际上是一个类,是一个和条件相关的一个类。
    需要等待一个条件达成,这个类需要和互斥量配合使用,需要生成一个类的对象
    A myobja;
    std::thread my_out_Thread(&A::outMsgRecvQueue,&myobja);//outMsgRecvQueue为起始函数的线程
    std::thread my_out_Thread2(&A::outMsgRecvQueue,&myobja);
    std::thread my_in_Thread(&A::inMsgRecvQueue,&myobja);//inMsgRecvQueue为起始函数的线程    
    outMsgRecvQueue.join();
    outMsgRecvQueue2.join();
    inMsgRecvQueue.join();     
    cout<<"主线程收尾,正常退出"<endl;
    return 0;
}

二、notify_all()

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: notify_one() 是 condition_variable 类的一个成员函数,它的作用是唤醒一个正在等待 condition_variable线程,使其获得锁并继续执行。它只会唤醒一个等待的线程,所以如果有多个线程在等待,那么只有一个线程会被唤醒,其他线程还是处于等待状态。使用 notify_one() 的方法是:在线程中使用 std::unique_lock 对象来锁定 condition_variable,然后调用 condition_variablewait() 方法来等待,当线程需要唤醒其他线程时,调用 notify_one() 来唤醒等待的线程。 ### 回答2: condition_variable中的notify_one()函数是C++标准库中用于通知等待在特定条件的线程的函数。当某个线程处于wait状态且在condition_variable上等待时,调用notify_one()函数可以唤醒其中的一个线程,使其继续执行。 notify_one()函数的用法较为简单,只需在需要唤醒线程的地方调用该函数即可。当有线程调用condition_variablewait()函数等待时,其他线程可以通过调用notify_one()函数来唤醒其中一个等待的线程。 需要注意的是,notify_one()函数并不会立即唤醒等待的线程,而是将其加入到就绪队列中,等待系统调度。因此不能确定哪个线程会被唤醒,也不能保证唤醒的顺序。如果需要唤醒多个线程,可以使用condition_variablenotify_all()函数。 notify_one()函数通常与unique_lock结合使用。在调用notify_one()之前,需要先获得与condition_variable关联的互斥锁,并在互斥锁的作用域内进行唤醒操作,以确保线程安全。 总的来说,condition_variable中的notify_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
发出的红包

打赏作者

aFakeProgramer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值