c ++ 11 multithreaded programming condition_variable Session Eight wait notify_one notify_all

 

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

wait () to wait for a thing
            // If the second argument the return value is true, then this line will continue to run down.
            // If the second parameter return value is false then the wait will unlock the mutex, and plug in this line
            // block to when? Block to other function calls notify_one () until the function
            // wait if there is no second argument, the second argument returns false the same effect.
            When using other functions notify_one will wait wake up, then wait will try again to acquire the lock.
            If you can not get the code on the card side in wait to acquire the lock if the lock is acquired, it will continue.
            1) After the wake-up wait, and the success of the next lock:
            If the second argument the return value is true, then this line will continue to run down.
            If the second parameter value is false then returns to wait unlocks the mutex, and clogging in the line, waiting for wakeup
            2) If the second parameter is not wait long as wake-up, once the lock is acquired, it is from the wait here continue down.
(2) deep thinking of the code above
(3) notify_all ()


Condition variable 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()

Published 101 original articles · won praise 73 · views 120 000 +

Guess you like

Origin blog.csdn.net/usstmiracle/article/details/104439351