C++多线程快速入门(二)共享数据同步以及数据竞争
目录
- std::unique_lock类模板
- 仅调用一次
- 线程局部存储
- 原子变量
- 往期内容回顾
std::unique_lock类模板
互斥锁保证了线程间的同步,却将并行操作变成了串行操作,对性能有较大影响,所以我们要尽可能减小锁的区间粒度。
lock_guard
只能保证在析构的时候进行解锁操作,所以其本身并没有提供加锁解锁的接口
class logFile{private:std::mutex mtx;ofstream f;
public:logFile() {f.open("log.txt");}~logFile() {f.close();}void sharedPrint(string msg, int id) {{std::lock_guard<std::mutex> guard(mtx);// do sth1}// do sth2// ...{std::lock_guard<std::mutex> guard(mtx);// do sth3f << msg << id << endl;cout << msg << id << endl;}}
};
上面代码中,sharedPrint函数内部有两段代码需要进行加锁保护,此时使用lock_guard就需要创建两个局部对象来管理同一个互斥锁。
其实可以使用unique_lock,它提供了**lock()和unlock()**接口,能记录现在处于上锁还是没上锁状态,在析构的时候,会根据当前状态来决定是否要进行解锁(lock_guard就一定会解锁)
void sharedPrint(string msg, int id) {std::unique_lock<std::mutex> guard(mtx);// do sth1guard.unlock(); // 临时解锁// do sth2guard.lock(); // 继续上锁// do sth3f << msg << id << endl;cout << msg << id << endl;// guard.unlock(); // 这个可要可不要,因为析构的时候也会自动执行的}
仅调用一次
程序免不了要初始化数据,线程并发没有某种同步手段来控制,会导致初始化函数多次运行。
c++11种提供仅调用一次的功能,首先声明一个once_flag类型的变量作为初始化标志,最好是静态、全局的,这样对于线程就是可见的了。然后调用专门的call_once()函数,以函数式编程的方式,传递这个标志和初始化函数,这样就可以保证,即使多个线程重入call_once(),也只能由一个线程会成功初始化
#include <iostream>
#include <thread>
#include <mutex>// 全局的初始化标志
static std::once_flag flag;
auto f = []()
{std::call_once(flag,[](){std::cout << "only once" << std::endl;});
};
int main() {// 启动两个线程,运行函数fstd::thread t1(f);std::thread t2(f);t1.join();t2.join();// std::cout << "finished" << std::endl;return 0;
}
实际编译结果如下:
only once
线程局部存储
当读写全局变量时,一般也会出现数据竞争,但是全局变量不一定是必须共享的,可能仅仅是为了方便线程传入传出数据,不是共享所有权。此时可以使用关键字thread_local
实现线程局部缓存,被其标志的变量在每个线程里都会有一个独立的副本。
#include <iostream>
#include <thread>int main() {// 启动两个线程,运行函数fthread_local int n = 0;auto f = [&](int x){n += x;std::cout << n << std::endl;};std::thread t1(f, 10);std::thread t2(f, 20);t1.join();t2.join();// std::cout << "finished" << std::endl;return 0;
}
结果是:
10
20
说明两个线程互不干扰,如果将变量声明改为static,两个线程会共享这个变量,导致连续加两次,结果是下面:
10 or 20
30 30
原子变量
对于非独占、必须共享的数据,要保证多线程读写共享数据一致就要解决同步问题,两个线程得互斥。但是mutex互斥量成本较高,可以使用atmoic原子化操作。
int main() {static std::atomic_flag flag {false}; // 原子化的标志量static atomic_int n; // 原子化的intauto f = [&](){auto value = flag.test_and_set(); // TAS检查原子标志量if (value) {std::cout << "flag has been set" << std::endl;} else {std::cout << "set flag by" << std::this_thread::get_id() << std::endl; // 输出线程id}n += 100; // 原子变量加法运算std::this_thread::sleep_for(std::chrono::seconds(5)); //线程睡眠std::cout << n << std::endl;};std::thread t1(f);std::thread t2(f);t1.join();t2.join();
}
往期内容回顾
C++多线程快速入门(一):基本&常用操作
C++多线程快速入门(二)共享数据同步以及数据竞争相关推荐
- C++多线程快速入门(五)简单线程池设计
目录 设计思路 主线程运行逻辑 task以及taskpool设计 详细流程讲解 完整代码 打印结果 往期回顾 设计思路 线程池实际上就是一组线程,当我们需要异步执行一些任务时,经常要通过OS频繁创建和 ...
- C++多线程快速入门(三):生产者消费者模型与条件变量使用
互斥锁完成 #include <iostream> #include <deque> #include <thread> #include <mutex> ...
- Java 高级 --- 多线程快速入门
这世上有三样东西是别人抢不走的:一是吃进胃里的食物,二是藏在心中的梦想,三是读进大脑的书 多线程快速入门 1.线程与进程区别 每个正在系统上运行的程序都是一个进程.每个进程包含一到多个线程.线程是一组 ...
- AS3多线程快速入门(三):NAPE物理引擎+Starling
原文:http://blog.domlib.com/articles/345 [更新]Adobe在11.4正式发布的最后一刻移除了ByteArray.shareable功能的支持,推迟到11.5版本再 ...
- AS3多线程快速入门(三):NAPE物理引擎+Starling[译]
原文链接:http://esdot.ca/site/2012/intro-to-as3-workers-part-3-nape-physics-starling [更新]Adobe在11.4正式发布的 ...
- C++多线程快速入门(一):基本常用操作
目录 case1:创建线程1 join.detach case2:创建线程2 线程传参 传值或者传引用 case3:创建线程 线程传参 functional object作为参数 case4:观察多线 ...
- Python3快速入门(十四)——Pandas数据读取
Python3快速入门(十四)--Pandas数据读取 一.DataFrame IO 1.CSV文件 pandas.read_csv(filepath_or_buffer, na_values='NA ...
- 【Python零基础快速入门系列 | 07】浪漫的数据容器:成双成对之字典
这是机器未来的第11篇文章 原文首发链接:https://blog.csdn.net/RobotFutures/article/details/125038890 <Python零基础快速入门系 ...
- Java 多线程快速入门(面试概念解答一)
Java 多线程快速入门 什么是进程,什么是线程,什么是多线程? 创建多线程有哪些方式? 启动线程是使用调用start方法还是run方法? 获取线程对象以及名称 守护线程 使用setDaemon(tr ...
最新文章
- unity 游戏第一次安装完之后运行,切出来,点击桌面图标后黑屏问题
- 【错误记录】Flutter 界面跳转报错 ( Navigator operation requested with a context that does not include a Naviga )
- 5个很常用的CSS3网页小实例
- 【小白学习PyTorch教程】十五、BERT:通过PyTorch来创建一个文本分类的Bert模型
- 感想总结——热烈庆祝CSDN博客排名进入前20000名
- 顺序三元组 java_hihocoder-1550-顺序三元组
- cuSPARSE库:(十七)cusparseStatus_t 返回信息
- 文学系列:《叶之震颤》读书笔记
- php点击表格单元格链接,详解PhpSpreadsheet单元格设置样式、图片、超链接等
- PyQt5保姆级教程-- 从入门到精通
- python最小二乘法求a b_最小二乘法公式推导及Python实现
- 道一MD5校验工具发布
- Adobe pr,ae,ps...软件的安装,及简单的使用
- 看英语数据手册很难?5步帮你搞定!
- 联通手机卡网速的修改
- 微信摇心愿如何选不同服务器,2020微信游戏摇心愿活动参与方法介绍
- Qt creator开发的C++应用程序运行崩溃,异常代码0xc0000409,错误偏移量0x0009efbb解决。
- c语言的论文,C语言论文
- FaceNet 人脸比对框架 部署+测试
- 钉钉API考勤打卡记录获取并存入数据库(python)
热门文章
- 基于nbu oj c语言答案,Just oj 2018 C语言程序设计竞赛(高级组)F:Star(结构体排序+最小生成树)...
- JSP+Tomcat+SQL Server 2000+JDBC实现合同信息管理系统
- 教你玩转CSS 伪类
- Shiro-550反序列化漏洞复现
- php html邮件,php发送HTML邮件
- matlab短均线滞后项,均线理论的滞后性问题
- php制图汉字,PHP用imageTtfText函数在图片上写入汉字
- 什么是URL转发和一个IP建多个Web站点--主机头名法
- js将canvas保存成图片并下载
- 插件开发-UI插件开发