Modern C++ 条件变量
今天无意中看到一篇帖子,关于条件变量的,不过仔细看看发现它并达不到原本的目的。
程序如下,读者可以先想想他的本意,以及有没有问题:
#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <unistd.h>
using namespace std;
//全局条件变量
condition_variable cond;
mutex _mutex;
int count = 0;void fun1(){while(1){count++;unique_lock<mutex>lock(_mutex);if(count%5 == 0){cond.notify_one();}else{cout<<"this is fun1,count="<<count<<endl;}lock.unlock();sleep(1);}
}void fun2()
{while(1){unique_lock<mutex>lock(_mutex);cond.wait(lock);cout<<"this is fun2,count="<<count<<endl;lock.unlock();sleep(2);}
}int main()
{thread t1(fun1);thread t2(fun2);t1.join();t2.join();return 0;
}
OK,本意显然是:
- 从1开始打印整数
- 线程t1, 打印非5的倍数
- 线程t2, 打印5的倍数
编译执行,运行的还不错,符合预期,但这都是sleep的功劳。把fun1中的sleep去掉,fun2中的sleep放到cond.wait(lock)后,它BUG的面目就暴露出来了:
void fun1(){while(1){count++;unique_lock<mutex>lock(_mutex);if(count%5 == 0){cond.notify_one();}else{cout<<"this is fun1,count="<<count<<endl;}lock.unlock();}
}void fun2()
{while(1){unique_lock<mutex>lock(_mutex);cond.wait(lock);sleep(2);cout<<"this is fun2,count="<<count<<endl;lock.unlock();}
}
[mzhai@lock]$ ./a.out this is fun1,count=1 this is fun1,count=2 this is fun1,count=3 this is fun1,count=4 this is fun2,count=6 this is fun1,count=6 this is fun1,count=7 this is fun1,count=8 this is fun1,count=9 this is fun1,count=11 this is fun1,count=12 this is fun1,count=13 this is fun1,count=14 this is fun1,count=16 this is fun1,count=17 this is fun1,count=18 this is fun1,count=19 this is fun1,count=21多线程结果不能因随机加了几个sleep就不同,加sleep仅仅是模拟线程调度不大一样了。
再回过头来看看代码哪些地方有问题:
- cond.notify_one(); count是5的倍数时,t1会通过notify_one通知t2做事,但并不会阻止t1继续执行。想想一下如果t1执行的很快而t2一直没得到调度,则t1会打印1,2,3,4,6,7,8,9,11...
- cond.wait(lock); 可能会假唤醒,此时t1并没有通知它。
那“this is fun2,count=6” 是怎么回事哪?不应该是5吗?一种可能性是(可以通过GDB调试来模拟):
说了那么多,怎么改哪?
这是一个典型的你等我我等你的例子,对于这个例子都是一方干完事情另一方才能继续,完全串休化的任务,直接写到一个线程里即可。如果说我为了练习线程同步技巧非要整两个线程,那也行,condition_variable官方文档上就有一个例子实现了main线程等待worker_thread完成任务:
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;void worker_thread()
{// Wait until main() sends datastd::unique_lock lk(m);cv.wait(lk, []{ return ready; });// after the wait, we own the lock.std::cout << "Worker thread is processing data\n";data += " after processing";// Send data back to main()processed = true;std::cout << "Worker thread signals data processing completed\n";// Manual unlocking is done before notifying, to avoid waking up// the waiting thread only to block again (see notify_one for details)lk.unlock();cv.notify_one();
}int main()
{std::thread worker(worker_thread);data = "Example data";// send data to the worker thread{std::lock_guard lk(m);ready = true;std::cout << "main() signals data ready for processing\n";}cv.notify_one();// wait for the worker{std::unique_lock lk(m);cv.wait(lk, []{ return processed; });}std::cout << "Back in main(), data = " << data << '\n';worker.join();
}
我们依样画葫芦:
#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <unistd.h>
using namespace std;
//全局条件变量
condition_variable cond;
mutex _mutex;
bool ready = false;
bool processed = false;int count = 0;void fun1(){while(1){count++;unique_lock<mutex> lock1(_mutex);if(count%5 == 0){ready = true;processed = false;lock1.unlock();cond.notify_one();lock1.lock();cond.wait(lock1, []{ return processed; });}else{cout<<"this is fun1,count="<<count<<endl;}lock1.unlock();}
}void fun2()
{while(1){unique_lock<mutex> lock1(_mutex);cond.wait(lock1, []{ return ready; });cout<<"this is fun2,count="<<count<<endl;processed = true;ready = false;lock1.unlock();cond.notify_one();}
}int main()
{thread t1(fun1);thread t2(fun2);t1.join();t2.join();return 0;
}
结果符合预期,感兴趣的读者可以到处插入sleep测试一下。
相关文章:
Modern C++ 条件变量
今天无意中看到一篇帖子,关于条件变量的,不过仔细看看发现它并达不到原本的目的。 程序如下,读者可以先想想他的本意,以及有没有问题: #include <iostream> #include <thread> #include <condition_v…...
免费chartGPT网站汇总--
https://s.suolj.com - (支持文心、科大讯飞、智谱等国内大语言模型,Midjourney绘画、语音对讲、聊天插件)国内可以直连,响应速度很快 很稳定 https://seboai.github.io - 国内可以直连,响应速度很快 很稳定 http://gp…...
关于C#中的async/await的理解
1. 使用async标记的方法被认为是一个异步方法,如果不使用await关键字,调用跟普通方法没有区别 static async Task Main(string[] args){Console.WriteLine("主线程id:" Thread.CurrentThread.ManagedThreadId);TestAwait();Consol…...
docker硬件交互 _ROS2
docker硬件交互 _ROS2 将自己需要挂载的设备接到主板上,在宿主机中建立udev规则(/etc/udev/rules.d/)然后在开启容器时,将设置了规则的devices 通过 --device/dev/myserial --device/dev/rplidar 等 参数挂载到docker容器中 doc…...
JS的数据类型和运算符
typeof()方法:检测数据类型 JS中的基本数据类型 基本数据类型 1.number 数字 2.string 字符串 3.boolean 布尔 4.null 代表空值(typeof方法检测出来的数据类型是object类型) 5.underfined 未定义;变量已声明但是未赋值 6.…...
CSS实现平行四边形
1、为什么实现平行四边形 在日常开发过程中,有些时候我们可以会遇到一种情况,如可视化大屏中要求我们横线实现对应的进度条,但进度条的内容是由无数个平行四边形组装类似于进度条的形式,那么我们就需要使用CSS来进行对应的实现。 …...
第11章 GUI Page500~504 步骤三十二:打开画板文件02
各个图元类新增GetTypeName_Static(),并将原来的GetTypeName()改为调用静态方法实现: 直线: 圆: 十字: 矩形: 文字: tool_4_save_load.hpp添加两行 tool_4_save_load.cpp增加: 增加…...
【ROS2】ROS2使用C++实现简单服务端
使用ROS2实现简单的服务端,功能为将客户端提供的两个数相加后返回给客户端。 代码如下: #include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/string.hpp" #include "base_interfaces_demo/msg/student.hpp" #include "base_interfac…...
WAF攻防相关知识点总结1--信息收集中的WAF触发及解决方案
什么是WAF WAF可以通过对Web应用程序的流量进行过滤和监控,识别并阻止潜在的安全威胁。WAF可以检测Web应用程序中的各种攻击,例如SQL注入、跨站点脚本攻击(XSS)、跨站请求伪造(CSRF)等,并采取相…...
行云部署前端架构解析-前言 | 京东云技术团队
一个简单的自我介绍 项目规模 截止目前上万次代码提交,总代码行数1超过21万行,其中人工维护的代码超过 13万行,近千个文件。 前端线上服务直接对接的后端服务,达十多个。 跟很多应用一样, 它有行云的入口, 也有独立的服务, 还…...
git提交代码到远端仓库的方法详解
一、何为git git就是版本控制器,就比如说你新建了一个git文件夹,里面用于存放你的C语言实习报告,现在要用git对该文件夹进行接管。当你修改了你的C语言实习报告点击保存之后,就用git的相关命令,提交给git,让…...
基于网络爬虫的天气数据分析
二、网络爬虫设计 网络爬虫原理 网络爬虫是一种自动化程序,用于从互联网上获取数据。其工作原理可以分为以下几个步骤: 定义起始点:网络爬虫首先需要定义一个或多个起始点(URL),从这些起始点开始抓取数据…...
Javaweb之SpringBootWeb案例员工管理之删除员工的详细解析
3.3 删除员工 查询员完成之后,我们继续开发新的功能:删除员工。 3.3.1 需求 当我们勾选列表前面的复选框,然后点击 "批量删除" 按钮,就可以将这一批次的员工信息删除掉了。也可以只勾选一个复选框,仅删除一…...
写点东西《什么是网络抓取?》
写点东西《什么是网络抓取?》 什么是网络抓取? 网络抓取合法吗? 什么是网络爬虫,它是如何工作的? 网络爬虫示例 网络抓取工具 结论 您是否曾经想同时比较多个网站上同一件商品的价格?或者自动提取您最喜欢的…...
使用C#操作文件:一个实际案例——替换文件中的IP地址
标题: 使用C#操作文件:一个实际案例——替换文件中的IP地址 介绍: 欢迎阅读我的最新博客!今天,我们将探讨如何使用C#来处理一个实际的编程挑战:读取一个配置文件并替换其中的IP地址。这是一个非常常见的…...
Zookeeper简介
系列文章目录 Zookeeper安装教程 目录 一、Zookeeper简介 二、Zookeeper的数据结构 三、CPA理论 四、BASE 理论 五、ZooKeeper的特性 前言 这是我的学习笔记,以便后面翻阅。 一、Zookeeper简介 ZooKeeper是一个分布式的、开放源码的分布式应用程序协调服务&a…...
第33集《佛法修学概要》
请大家打开讲义第八十七页。我们讲到六度法门,这是菩萨道的六度。 佛教的修学,从浅入深,大致上可以分成三个主要的次第: 我们刚开始修学佛法的时候,第一个修学的重点,叫作“见山是山,见水是水…...
C++ 之LeetCode刷题记录(十三)
😄😊😆😃😄😊😆😃 开始cpp刷题之旅。 依旧是追求耗时0s的一天。 70. 爬楼梯 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可…...
容器技术1-容器与镜像简介
目录 1、容器与虚拟化 2、容器发展历程 3、镜像简介 4、镜像原理 (1)分层存储 (2)写时复制 (3)内容寻址 (4)联合挂载 1、容器与虚拟化 容器技术在操作系统层面实现了对计算机…...
openssl3.2 - 官方demo学习 - smime - smdec.c
文章目录 openssl3.2 - 官方demo学习 - smime - smdec.c概述笔记END openssl3.2 - 官方demo学习 - smime - smdec.c 概述 从pem证书中得到x509*和私钥, 用私钥和证书解密MIME格式的PKCS7密文, 并保存解密后的明文 MIME的数据操作, 都是PKCS7相关的 笔记 /*! \file smdec.c …...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...
智能职业发展系统:AI驱动的职业规划平台技术解析
智能职业发展系统:AI驱动的职业规划平台技术解析 引言:数字时代的职业革命 在当今瞬息万变的就业市场中,传统的职业规划方法已无法满足个人和企业的需求。据统计,全球每年有超过2亿人面临职业转型困境,而企业也因此遭…...
Yii2项目自动向GitLab上报Bug
Yii2 项目自动上报Bug 原理 yii2在程序报错时, 会执行指定action, 通过重写ErrorAction, 实现Bug自动提交至GitLab的issue 步骤 配置SiteController中的actions方法 public function actions(){return [error > [class > app\helpers\web\ErrorAction,],];}重写Error…...
CMS内容管理系统的设计与实现:多站点模式的实现
在一套内容管理系统中,其实有很多站点,比如企业门户网站,产品手册,知识帮助手册等,因此会需要多个站点,甚至PC、mobile、ipad各有一个站点。 每个站点关联的有站点所在目录及所属的域名。 一、站点表设计…...
接口 RESTful 中的超媒体:REST 架构的灵魂驱动
在 RESTful 架构中,** 超媒体(Hypermedia)** 是一个核心概念,它体现了 REST 的 “表述性状态转移(Representational State Transfer)” 的本质,也是区分 “真 RESTful API” 与 “伪 RESTful AP…...
