• c++11 并发编程 --- 条件变量(condition_variable) wait,wait_for


    介绍condition_variable, wait,wait_for
    直接上代码如下:

    #include <iostream>                // std::cout
    #include <thread>                // std::thread
    #include <mutex>                // std::mutex, std::unique_lock
    #include <condition_variable>    // std::condition_variable
    
    std::mutex mtx; // 全局互斥锁.
    std::condition_variable cv; // 全局条件变量.
    bool ready = false; // 全局标志位.
    
    
    void do_print_id(int id)
    {
        std::unique_lock <std::mutex> lck(mtx); // 加锁互斥量
        while (!ready) 
        {
            cv.wait(lck); // 当ready==false的时候,while语句执行到wait这里,然后就堵塞到这行,等到通知信号,同时解锁互斥量,不影响其他线程获取锁。 
        }                 //当 cv.notify_all(); // 唤醒所有线程. 执行到这句wait就收到了信号就被唤醒开始干活,首先就是不断的尝试重新获取并加锁互斥量。
                          //若获取不到锁就卡在这里反复尝试加锁
                          //若获取到了锁才往下执行
      
        std::cout << "thread " << id << '
    ';
    }
    
    void go()
    {
        std::unique_lock <std::mutex> lck(mtx);
        ready = true; // 设置全局标志位为 true.
        cv.notify_all(); // 唤醒所有线程.
    }
    
    int main()
    {
        std::thread threads[10];
        // spawn 10 threads:
        for (int i = 0; i < 10; ++i)
            threads[i] = std::thread(do_print_id, i);
    
        std::cout << "10 threads ready to race...
    ";
        go(); // go!
    
      for (auto & th:threads)
            th.join();
    
        return 0;
    }
    

    wait_for

    与std::condition_variable::wait() 类似,不过 wait_for可以指定一个时间段,在当前线程收到通知或者指定的时间 rel_time 超时之前,该线程都会处于阻塞状态。
    而一旦超时或者收到了其他线程的通知,wait_for返回,剩下的处理步骤和 wait()类似。

    #include <iostream>           // std::cout
    #include <thread>             // std::thread
    #include <chrono>             // std::chrono::seconds
    #include <mutex>              // std::mutex, std::unique_lock
    #include <condition_variable> // std::condition_variable, std::cv_status
    std::condition_variable cv;
    int value;
    void do_read_value()
    {
        std::cin >> value;
        cv.notify_one(); //只有键盘敲入一个字符,才往下执行cv.notify_one();
    }
    
    int main ()
    {
        std::cout << "Please, enter an integer (I'll be printing dots): 
    ";
        std::thread th(do_read_value);
        std::mutex mtx;
        std::unique_lock<std::mutex> lck(mtx); //加锁互斥量
        while (cv.wait_for(lck,std::chrono::seconds(1)) == std::cv_status::timeout) { //这里wait_for堵塞到这一行,解锁互斥量。
                   std::cout << '.';                                                  //当超时1s的时候,相当于收到了通知信号,就被唤醒干活了。 加锁互斥量
                   std::cout.flush();                                                 //while语句满足就执行打印.
        }                                                                             //然后再次循环再wait等待1s,循环反复。
                                                                                      //但是当收到cv.notify_one();的时候,不满足 std::cv_status::timeout,就会退出循环。
        std::cout << "You entered: " << value << '
    ';                                //这个时候不断尝试加锁互斥量,加锁成功往下执行。加锁不成功不断尝试加锁。
        th.join();
        return 0;
    }
    

    这里的现像就是终端不断的在打印.

    Please, enter an integer (I'll be printing dots): 
    .................................
    

    当我敲一个字符的时候,就会停止打印

    Please, enter an integer (I'll be printing dots): 
    ...............................................................................q.
    You entered: 0
    按 <RETURN> 来关闭窗口...
    

    在多线程任务中,往往需要多个线程往同一个队列添加或者取数据,就需要用到条件变量,当你push了一个数据到队列,你就可以通知另外取数据的线程可以去取数据了。
    当你取走一个数据的时候,你就可以通知压(push)数据的线程可以往线程压数据了,队列刚刚空出一个位置了就可以压数据了。
    代码如下:

    #include <mutex>      
    #include <deque>
    #include <condition_variable>
    
    
    template <class T>
    class my_buffer
    {
    public:
    	my_buffer(const char* name, int max_size = 30)
    		:_terminal(false)
    		, _max_size(max_size)
    		, _name(name)
    		, _last_warning_time(0)
    	{
    
    	}
    
    	~my_buffer(void)
    	{
    	}
    
    	bool push(const T& value)
    	{
    		std::unique_lock <std::mutex> lck(_mutex);
    		while (_job_list.size() >= _max_size && !_terminal)
    		{
    			_push_cond.wait(lck);
    		}
    
    		if (_terminal)
    		{
    			return false;
    		}
    
    		_job_list.push_back(value);
    		_pop_cond.notify_one();//push了一个数据就可以通知取数据pop的线程有数据可以取了。
    		return true;
    	}
    
    	bool async_push(const T& value, float& capacity_rate)
    	{
    		std::unique_lock <std::mutex> lck(_mutex);
    		/*while (_job_list.size() >= _max_size && !_terminal)
    		{
    			_push_cond.wait(lck);
    		}*/
    
    		if (_job_list.size() >= _max_size)
    		{
    			capacity_rate = _job_list.size() / ((float)_max_size);
    			return false;
    		}
    
    		/*if (_terminal)
    		{
    			return false;
    		}*/
    
    		_job_list.push_back(value);
    		_pop_cond.notify_one();//push了一个数据就可以通知取数据pop的线程有数据可以取了。
    
    		capacity_rate = _job_list.size() / ((float)_max_size);
    		return true;
    	}
    
    	bool push_front(const T& value)
    	{
    		std::unique_lock <std::mutex> lck(_mutex);
    		while (_job_list.size() >= _max_size && !_terminal)
    		{
    			_push_cond.wait(lck);
    		}
    
    		if (_terminal)
    		{
    			return false;
    		}
    
    		_job_list.push_front(value);
    		_pop_cond.notify_one();//push了一个数据就可以通知取数据pop的线程有数据可以取了。
    		return true;
    	}
    
    	bool pop(T& value)
    	{
    		std::unique_lock <std::mutex> lck(_mutex);
    		while (_job_list.empty() && !_terminal)
    		{
    			_pop_cond.wait(lck);
    		}
    			
    		if (_terminal)
    		{
    			return false;
    		}
    
    		value = *_job_list.begin();
    		_job_list.pop_front();
    		_push_cond.notify_one();//取走一个数据就可以通知压数据的条件变量了
    
    		return true;
    	}
    
    	bool pop_wait(T& value, int second)
    	{
    		std::unique_lock <std::mutex> lck(_mutex);
    		if (_job_list.empty())
    		{
                if (std::cv_status::timeout == _pop_cond.wait_for(lck, std::chrono::milliseconds(second)))
    			{
    				return false;
    			}		
    		}
    
    		value = *_job_list.begin();
    		_job_list.pop_front();
    		_push_cond.notify_one();//取走一个数据就可以通知压数据的条件变量了
    
    		return true;
    	}
    	
    	void clear(void)
    	{
    		_terminal = true;
    		_push_cond.notify_all();
    		_pop_cond.notify_all();
    	}
    
    	void flush(void)
    	{
    		std::unique_lock <std::mutex> lck(_mutex);
    		_job_list.clear();
    	}
    
    	void reset(void)
    	{
    		_terminal = false;
    	}
    
    	size_t size(void)
    	{
    		std::unique_lock <std::mutex> lck(_mutex);
    		return _job_list.size();
    	}
    
    	float capacity_rate(void)
    	{
    		std::unique_lock <std::mutex> lck(_mutex);
    		return _job_list .size()/ ((float)_max_size);
    	}
    private:
    	std::deque<T> _job_list; //队列				
    	std::mutex _mutex;  //互斥量						
    	std::condition_variable _pop_cond;		
    	std::condition_variable _push_cond;	
    	volatile bool _terminal;				
    	unsigned long _max_size;//容器最大空间
    	std::string _name;
    	time_t _last_warning_time;
    }; 
    
    好记性不如烂键盘---点滴、积累、进步!
  • 相关阅读:
    sizeof注意
    如何获取存储过程的返回值和输出值
    OA、ERP、SRM、PLM、CAPP、MES、LIMS、CRM
    js1号脚本
    Python各类常用库整理
    Html设计器
    python从入门到放弃之图像处理
    C# Web API操作Sqlite数据库
    C# Naudio 从麦克风输入到声卡输出 录音 放音功能
    WPF/MVVM模式入门教程(二):实现INotifyPropertyChanged接口
  • 原文地址:https://www.cnblogs.com/yanghailin/p/15428288.html
Copyright © 2020-2023  润新知