admin管理员组文章数量:1599529
系列文章目录
文章目录
- 系列文章目录
- 前言
- 一、基本概念
- 1.1 std::condition_variable
- 1.2 wait()函数
- 1.2.1 wait()带第二个参数
- 1.2.2 wait()不带第二个参数
- 1.2.3 当其他线程用notify_one()或notify_all()
- 1.3 notify函数
- 二、代码实例
- 总结
前言
C++11多线程,wait()和notify()的使用。
一、基本概念
1.1 std::condition_variable
private:
std::condition_variable my_cond; //生成一个条件变量对象
- 条件变量std::condition_variable、wait()、notify_one():只能通知一个outMsgRecvQueue线程。
std::condition_variable
实际上是一个类
,是一个和条件相关的一个类,说白了就是等待一个条件达成。- 这个类需要和互斥量来配合工作,用的时候我们要生成这个类的对象;
1.2 wait()函数
1.2.1 wait()带第二个参数
wait()用来等一个东西,运行到这一行代码会进行判断。
//这里wait()是带第二个参数的。
my_cond.wait(sbguard1, [this] { //一个lambda就是一个可调用对象(函数)
if (!msgRecvQueue.empty())
return true;
return false;
});
msgRecvQueue.empty(),是用来判断队列是否为空,自己写的函数,可参考章节二代码实例
- 如果第二个参数lambda表达式返回值是true,那wait()直接返回,不堵塞。
- 如果第二个参数lambda表达式返回值是false,那么wait()将解锁互斥量,并堵塞到本行,
那堵塞到什么时候为止呢?
答:堵塞到其他某个线程调用notify_one()或notify_all()成员函数为止
1.2.2 wait()不带第二个参数
my_cond.wait(sbguard1);
那么就跟第二个参数lambda表达式返回false效果一样
wait()将解锁互斥量,并堵塞到本行,堵塞到其他某个线程调用notify_one()成员函数为止;
1.2.3 当其他线程用notify_one()或notify_all()
会将本wait(原来是睡着/堵塞)的状态唤醒后,wait就开始恢复干活了,恢复后wait干什么活?
a)
wait()不断的尝试重新获取互斥量锁,如果获取不到,那么流程就卡在wait这里等着获取,如果获取到了锁(等于加了锁),那么wait就继续执行b
;
b)
有以下三个如果
b.1)
如果wait有第二个参数(lambda),就判断这个lambda表达式,如果lambda表达式为false,那么wait又对互斥量解锁,然后又休眠在这里等待再次被notify_one唤醒
b.2)
如果lambda表达式为true,则wait返回,流程走下来(此时互斥锁被锁着)。
b.3)
如果wait没有第二个参数,则wait返回,流程走下来。
1.3 notify函数
//my_cond.notify_one();
my_cond.notify_all();
notify_one():只能通知一个指定的线程。
notify_all():通知所有线程。
二、代码实例
#include <stdio.h>
#include <tchar.h>
#include <SDKDDKVer.h>
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <thread>
#include <list>
#include <mutex>
#include <condition_variable>
using namespace std;
class A
{
public:
//把收到的消息(玩家命令)入到一个队列的线程
void inMsgRecvQueue() //unlock()
{
for (int i = 0; i < 100000; ++i)
{
std::unique_lock<std::mutex> sbguard1(my_mutex1);
cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;
msgRecvQueue.push_back(i);
//假设这个数字i就是我收到的命令,我直接弄到消息队列里边来;
//假如outMsgRecvQueue()正在处理一个事务,需要一段时间,而不是正卡在wait()那里等待你唤醒,那么此时这个notify_one()这个调用也许就没效果;
//my_cond.notify_one();
//我们尝试把wait()的线程唤醒,执行完这行,那么outMsgRecvQueue()里边的wait就会被唤醒
//唤醒之后的事情后续研究;
my_cond.notify_all();
//......
//其他处理代码;
}
return;
}
//把数据从消息队列中取出的线程:
void outMsgRecvQueue()
{
int command = 0;
while (true)
{
std::unique_lock<std::mutex> sbguard1(my_mutex1);
my_cond.wait(sbguard1, [this] { //一个lambda就是一个可调用对象(函数)
if (!msgRecvQueue.empty())
return true;
return false;
});
//流程只要能走到这里来,这个互斥锁一定是锁着的。
//一会再写其他的...
command = msgRecvQueue.front(); //返回第一个元素,但不检查元素是否存在;
msgRecvQueue.pop_front(); //移除第一个元素,但不返回;
cout << "outMsgRecvQueue()执行,取出一个元素: " << command << "threadid = " << std::this_thread::get_id() << endl;
sbguard1.unlock(); //因为unique_lock的灵活性,所以我们可以随时的unlock解锁,以免锁住太长时间
//执行一些其他的动作,帮助玩家抽卡,抽卡需要100毫秒的处理时间;
//...
//执行100毫秒
//
} //end while
}
private:
std::list<int> msgRecvQueue; //容器,专门用于代表玩家给咱们发送过来的命令。
std::mutex my_mutex1; //创建一个互斥量(一把锁头)
std::condition_variable my_cond; //生成一个条件变量对象
};
int main()
{
A myobja;
std::thread myOutnMsgObj(&A::outMsgRecvQueue, &myobja); //第二个参数 引用,才能保证线程里 用的是同一个对象
std::thread myOutnMsgObj2(&A::outMsgRecvQueue, &myobja);
std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);
myInMsgObj.join();
myOutnMsgObj.join();
myOutnMsgObj2.join();
return 0;
}
总结
(1)了解wait()的使用(对锁 的影响),以及第二参数有无的区别;
(2)condition_variable、wait()、notify_one()或notify_all()如何配合工作。
(3)理解如何处理线程之间的交互联系?
本文标签: 多线程conditionvariablenotifyallnotifyonewait
版权声明:本文标题:C++11多线程:condition_variable、wait()、notify_one()、notify_all()的使用。 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/xitong/1728322059a1153952.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论