使用条件变量
在实际应用中使用生产者-消费者模型。
例如有一个消息队列,我们有一个消息产生线程,作为生产者;有多个读取线程,作为消费者。
对于之前的小型案例中模拟了这一过程;在读取线程中直接使用锁来和sleep来等待消息队列中产生消息,自然会由于sleep产生延时,为了减少延时改用条件变量。
生产线程使用条件,通常使用以下步骤:
- 准备信号变量:std::condition_variable cv
- 获得锁,通常为unique_lock
- 对消息队列进行修改
- 释放锁并通知读取线程,通知可以使用one或者all来通知一个或多个线程
对于读取线程,通常也有如下几个步骤:
- 获得共享锁
- 等待信号变量,等待使用wait函数,通常有默认形式和lambda表达式两种
- 处理消息
实例
现在提供一个写入线程和多个读取线程,使用条件变量来实现此功能
准备
先声明锁、条件变量以及一个消息队列和若干头文件
1 |
|
写入线程
直接上代码:
1 | void ThreadWrite() |
cv.notify_one()用于通知一个读取线程
cv.notify_all()用于通知所有读取线程
读取线程
1 | void ThreadRead(int ThreadId) |
启动线程
1 | void test() |
修改之前案例
之前的小型案例中并未使用条件变量,所以将该案例稍加修改,使用条件变量来处理消息
新增额外变量
使用条件变量首先要包含condition_variable头文件
在MsgServer的头文件中增加条件变量
1 | std::condition_variable cv; |
修改写入线程
在写入完数据后,将锁释放并通知线程
1 | void MsgServer::SendMsg(std::string Msg) |
修改读取线程
1 | // 处理最大延时 |
以上是一般形式,但当写入线程写入万所有消息后读取线程会一直阻塞不会退出运行,所以要对退出条件做出一些修改:
首先要重写ThreadStop函数,在stop时发送一条通知;在wait时使用lambda表达式获取退出条件:
1 | virtual void ThreadStop() |
SetExit是额外增加的函数,用于设置bExit为true。
之后再做测试便发现写入线程写入完消息后便会自动退出。
小结
主要介绍了条件变量的使用方法和应用场景。
相比与之前的使用锁的方式,使用条件变量减少了处理消息时的延迟,但相应的也应注意线程的退出条件修改,否则会造成线程一直阻塞。
- 本文作者: KongXinQing
- 本文链接: https://13114987559.github.io/2024/04/01/note/C++多线程入门:使用条件变量/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!