C++并发与多线程学习笔记--线程之间调度
- condition_variable
- wait()
- notify_one
- notify_all
condition_variable
条件变量的实际用途:
比如有两个线程A和B,在线程A中等待一个条件满足,(消息队列中有要处理的消息),线程B专门往队列中丢数据。当B往线程中放入数据,同时B通知线程A,开始往下执行。在服务器的后台设计中,有一个线程,阻塞式地读取消息,并且将其解析,放入队列中,此时线程B还通知A,要从队列中去拿请求,并进行处理。

a) socket技术使得服务器中的程序能够像打开文件一样来读取数据。
b) 线程B读取数据,并将其放入到消息队列中。
c) 线程B唤醒线程A,让线程A从队列中拿数据。
d) 服务器处理请求完成并返回结果。
通过条件变量类可以使得A等待B:
复习原先的代码:(通过双重锁定,使得每次都判断是否为空,如果为空那么就取得锁)
class ProcessRequest {
public:
//把命令加入到一个队列
void inMsgRecvQueue() {
for (int i = 0; i < 100000; ++i) {
//std::lock_guard<std::mutex> sbguard(my_mutex);
cout << "插入一个元素" << endl;
m_msgRecvQueue.push_back(i); //假设这个队列表示玩家的命令
} //占用时间片
}
bool outMsgLULProc(int &command) {
//通过双重锁定,避免每次进来程序都锁定。
if (!m_msgRecvQueue.empty())
{
std::lock_guard<std::mutex> sbguard(my_mutex);
if (!m_msgRecvQueue.empty()) {
int command = m_msgRecvQueue.front();
m_msgRecvQueue.pop_front();
return true;
}
return false;
}
}
//把命令移出一个队列
void outMsgRecvQueue() {
int command = 0;
for (int i = 0; i < 100000; ++i) {
bool result = outMsgLULProc(command);
if (result == true) {
cout << "outMsgRecvQueue() 执行,取出一个元素" << endl;
}
else
{
cout << "outMsgRecvQueue() 还执行,但是消息队列为空" << endl;
//消息队列为空
}
//占用时间片
}
}
private:
std::list<int> m_msgRecvQueue; //容器,用于表示玩家的发送过来命令
std::mutex my_mutex;
};
使用类std::condition_variable来替代双重锁定,用来等待一个条件达成,这个类需要和互斥量配合工作,用的时候需要生成类的对象。
pirvate:
std::condition_variable my_condition;
wait()
出队列修改: wait是卡在这里的,需要修改入队列的线程。
void outMsgRecvQueue() {
int command = 0;
while (true) {
std::unique_lock<std::mutex> sbguard1(my_mutex);
my_condition.wait(sbguard1, [this] {
if (!m_msgRecvQueue.empty())//lambda表达式就是一个可调用对象(函数)
return true;
else
return false;
}); //wait用来等待一个东西
//Wait(para1, para2)
//para1: 互斥量
//para2:第二个参数Lambda表达式的返回值是False
// 那么将解锁互斥量,并阻塞本行,直到其他线程调用 notify_one()
//如果没有第二个参数,那么就跟第二个参数返回False效果一样
}
}
当然wait()之后可以提早解开 unique_lock(),然后执行逻辑。
notify_one
将原来阻塞的进程唤醒了。wait就开始恢复干活了,恢复之后
a) wait() 不断尝试获取互斥量锁,尝试拿这个锁。如果获取不到锁,流程就卡在wait这里,如果获取到,wait就走下来了。
b) 实际上获取到了锁就等于上了锁。如果wait有第二个参数(lambda),就判断lambda表达式,
如果表达式为false,又将互斥量解锁。然后另一个线程又休眠。
如果表达式为true,则wait返回,流程走下来(此时互斥锁被锁着)。
如果wait没有第二个参数,则wait返回
void inMsgRecvQueue() {
for (int i = 0; i < 100; ++i) {
std::lock_guard<std::mutex> sbguard(my_mutex);
m_msgRecvQueue.push_back(i); //假设这个队列表示玩家的命令
cout << "插入一个元素" << endl;
my_condition.notify_one();
} //占用时间片
}
同时获取锁的可能性:
1) void inMsgRecvQueue()
2) void outMsgRecvQueue()
可能出现同时竞争一个锁的可能性,也就是说如果运行到了outMsgRecvQueue()的逻辑执行语句的时候,队列中至少进去了一个元素,那么就有可能出现in和out并不是按序执行的情况。
out在执行逻辑语句的时候有延迟,此时如果in唤醒,out并不是卡在wait()的状态,那么此时notify_one()调用就没有效果。
深入思考
写代码用在商业中,必须理解。
在线程入口函数中, 队列中可能会存在多条数据,这个时候处理不过来怎么办?开更多的线程处理?或者限流,超过200条数据未处理,就卡住?
notify_all
C++并发与多线程学习笔记--线程之间调度的更多相关文章
- C++并发与多线程学习笔记--基本概念和实现
基本概念 并发 可执行程序.进程.线程 学习心得 并发的实现方法 多进程并发 多线程并发 总结 C++标准库 基本概念 (并发.进程.线程)区分C++初级编程和中高级编程 并发 两个或者更多的任务同时 ...
- C++并发与多线程学习笔记--单例设计模式、共享数据分析
设计模式 共享数据分析 call_once 设计模式 开发程序中的一些特殊写法,这些写法和常规写法不一样,但是程序灵活,维护起来方便,别人接管起来,阅读代码的时候都会很痛苦.用设计模式理念写出来的代码 ...
- C++并发与多线程学习笔记--参数传递详解
传递临时对象 陷阱 总结 临时对象作为线程参数 线程id的概念 临时对象构造时的抓捕 成员函数指针做线程函数 传递临时对象作为线程参数 创建的工作线程不止一个,线程根据编号来确定工作内容.每个线程都需 ...
- 【多线程】Android多线程学习笔记——线程池
Java线程池采用了享元设计模式,在系统中维持一定数量的线程,用于处理异步或并发需求,在平时处理异步或并发任务时被广泛使用.这里基于JDK1.8和Android28来整理一些关于线程池的知识点. 一. ...
- C++并发与多线程学习笔记--future成员函数、shared_future、atomic
std::future的其他成员函数 std::shared_future 原子操作.概念.基本用法 多线程主要是为了执行某个函数,本文的函数的例子,采用如下写法 int mythread() { c ...
- C++并发与多线程学习笔记--互斥量、用法、死锁概念
互斥量(mutex)的基本概念 互斥量的用法 lock(), unlock() std::lock_guard类模板 死锁 死锁演示 死锁的一般解决方案 std::lock()函数模板 std::lo ...
- C++并发与多线程学习笔记--atomic
std::atomic std::async std::atomic 一般atomic原子操作,针对++,--,+=,^=是支持的,其他结果可能不支持. 注意 std::atomic<int&g ...
- C++并发与多线程学习笔记--多线程数据共享问题
创建和等待多个线程 数据和共享问题分析 只读的数据 有读有写 其他案例 共享数据的保护案例代码 创建和等待多个线程 服务端后台开发就需要多个线程执行不同的任务.不同的线程执行不同任务,并返回执行结果. ...
- C++并发与多线程学习笔记--async、future、packaged_task、promise
async future packaged_task promise async std:async 是个函数,用来启动一个异步任务,启动起来一个异步任务之后,返回一个std::futre对象,启动一 ...
随机推荐
- GitHub Classroom
GitHub Classroom GitHub Education https://classroom.github.com/classrooms https://classroom.github.c ...
- react & redux data flow diagram
react & redux data flow diagram Redux 数据流程图
- puppeteer & screenshot
puppeteer & screenshot http://localhost:9812/screenshot?url=https://cdn.xgqfrms.xyz/
- Node.js & 页面截图 & 生成画报
Node.js & 页面截图 & 生成画报 https://zzk.cnblogs.com/my/s/blogpost-p?Keywords=headless solution 使用 ...
- Nestjs mongodb
nestjs 文档 mongoose 文档 使用"@meanie/mongoose-to-json"转换查询后返回的json数据 将"_id"转为"i ...
- NGK全球行伦敦站,SPC推动全球数字金融创新
近日,NGK全球巡回路演在英国的首都伦敦盛大落幕,此次路演有幸邀请到了西欧区块链业界弗洛伊德大咖,NGK方面代表鲍利斯以及英国及其组周边国家社群意见代表马丁内斯等人,总计参与人数达到了数十人. 路演一 ...
- NGK” 呼叫河马 “智能合约火爆全网
最近有一款基于NGK.IO公链上的智能合约"呼叫河马"在区块链市场很火.通过访问和查阅资料可知,"呼叫河马"是一款全新的智能合约Dapp小游戏,智能合约代码是1 ...
- HQYJ嵌入式学习笔记——C语言复习day1
第一天:Linux命令 vim操作 第二天:数据类型 运算符 顺序语句第三天:分支语句 循环语句第四天:循环语句 数组第五天:数组第六天:指针第七天:函数 数组与指针第八天:数组指针第九天:递归 第十 ...
- 12_MySQL如何对查询结果进行排序
本节所涉及的sql语句: -- 排序关键字 SELECT empno,ename,hiredate FROM t_emp ORDER BY hiredate DESC; -- 排序字段相同的情况 SE ...
- 2021-2-22:请你说下 CAP 理论并举例
CAP CAP 理论是分布式系统中的一个老生常谈的理论了,最早由 Eric Brewer 在一个讲座中提出.在这个讲座中,在传统 ACID 理论以及当时比较流行但是比较抽象的的设计指导理论 BASE ...