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++多线程快速入门(一):基本&常用操作

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/376833.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DNS安全浅议、域名A记录(ANAME),MX记录,CNAME记录

相关学习资料 http://baike.baidu.com/link?url77B3BYIuVsB3MpK1nOQXI-JbS-AP5MvREzSnnedU7F9_G8l_Kvbkt_O2gKqFw7vm http://www.rfc-editor.org/rfc/rfc1035.txt http://www.rfc-editor.org/rfc/rfc3596.txt http://www.rfc-editor.org/rfc/rfc2782.txt http://www.rfc-edito…

ThinkInJava4读书笔记之第一章对象入门

那句话怎么说来着&#xff0c;原句记不住了好像是出来混的迟早要还的。话说当初学校刚开Java课程&#xff0c;自己没有好好学啊&#xff0c;后来直接做了jsp和servlet&#xff0c;然后学了SSH框架和Extjs、jQuery&#xff0c;接着是mybatis&#xff08;ibatis&#xff09;、fre…

C++多线程快速入门(三):生产者消费者模型与条件变量使用

互斥锁完成 #include <iostream> #include <deque> #include <thread> #include <mutex>std::deque<int> q; std::mutex mtx;static void produce(int val) {while(val--) {std::unique_lock<std::mutex> guard(mtx);q.push_front(val);m…

【blade利刃出鞘】一起进入移动端webapp开发吧

前言 在移动浪潮袭来的时候&#xff0c;小钗有幸进入框架组做webapp框架开发&#xff0c;过程中遇到了移动端的各种坑&#xff0c;也产生了各种激情&#xff0c;就我们公司的发展历程来说 第一阶段&#xff1a;使用传统方式开发移动站点&#xff0c;少量引入HTML5元素 第二阶段…

题目理解。。

有时候一道大水题&#xff0c;因为英文描述可能有点复杂或者其它云云&#xff0c; 就比如那道PRO。。 别先被一道题吓一跳&#xff0c;&#xff0c;&#xff0c; 英文描述看深入一点总归会能解决的&#xff0c;尽可能多的考虑情况。大胆尝试。转载于:https://www.cnblogs.com/c…

C++多线程快速入门(四)shared_mutex以及读写锁应用

在前面的三讲中我们使用的mutex都是普通的std::mutex&#xff0c;这里介绍一下shared_mutex&#xff0c;版本为C17 std::shared_mutex的底层实现时操作系统提供的读写锁&#xff0c;在读多写少的情况下&#xff0c;该shared_mutex比mutex更加高效。 它提供了常用的四种方法&am…

Tornado/Python 学习笔记(一)

1.源代码下载及安装&#xff1a;http://www.tornadoweb.org/en/stable/ 2.python中xmlrpc库官方文档&#xff1a;https://docs.python.org/3/library/xmlrpc.html?highlightxmlrpc 3.xml介绍与学习&#xff1a;http://www.w3school.com.cn/xml/xml_intro.asp XML 被设计为传输…

spring-aop-annotation

1。假设你已经配好依赖注入那一块。此时的bean.xml为 <?xml version"1.0" encoding"UTF-8"?><beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns:cont…

c++实现简单线程池代码

目录完整代码TaskPool.cppTaskPool.hmain.cpp完整代码 TaskPool.cpp // // Created by LENOVO on 2021/10/25. //#include "TaskPool.h" #include <functional>std::mutex printMutex;TaskPool::TaskPool() : m_bRunning(false) {}TaskPool::~TaskPool() {re…

Android静态图片人脸识别的完整demo(附完整源码)

Demo功能&#xff1a;利用android自带的人脸识别进行识别&#xff0c;标记出眼睛和人脸位置。点击按键后进行人脸识别&#xff0c;完毕后显示到imageview上。 第一部分&#xff1a;布局文件activity_main.xml [html] view plaincopyprint?<RelativeLayout xmlns:android&qu…

图论:最短路径搜索--Dijkstra算法(c代码实现)

最近因为辞职&#xff0c;有不少闲功夫&#xff0c;重温下数据结构&#xff0c;顺便练练手。今天说说最短路径搜索算法中的Dijkstra原理和实现。 一&#xff1a;简介 这个算法用于解决图中单源最短路径问题。所谓单源节点是指给定源节点&#xff0c;求图中其它节点到此源节点的…

C++多线程快速入门(五)简单线程池设计

目录设计思路主线程运行逻辑task以及taskpool设计详细流程讲解完整代码打印结果往期回顾设计思路 线程池实际上就是一组线程&#xff0c;当我们需要异步执行一些任务时&#xff0c;经常要通过OS频繁创建和销毁线程&#xff0c;不如直接创建一组在程序生命周期内不会退出的线程…

C--函数

函数:具有特定功能的代码段,分为库函数,自定义函数. 函数定义: 函数返回值类型 函数名(形式参数列表) { 代码段; return 返回值; } 注意:每个函数返回值最多只有一个.return是一个函数结束的标志. 形式参数(形参):函数定义时使用的虚拟参数名,用以接收函数调用是传递过来的实际…

公式系统 - TradeBlazer公式基础 - Bar数据

Bar数据 在介绍Bar数据之前&#xff0c;首先&#xff0c;我们需要讨论一下TradeBlazer公式的计算方法&#xff0c;针对上面介绍的各种公式类型&#xff0c;包含公式应用&#xff0c;在公式进行计算时&#xff0c;都是建立在基本数据源(Bar数据)之上&#xff0c;我们这里所谓的B…

C++网络编程快速入门(一):TCP网络通信基本流程以及基础函数使用

目录流程概述服务器端代码实现客户端代码实现函数和结构讲解sockaddr_in和sockaddrsocket &#xff1a; 创建一个socket连接bind &#xff1a;绑定地址以及端口号问题流程概述 客户端与服务器之间的网络通信基本原理如下所示&#xff0c;复杂一点的架构可能会添加消息中间件。…

php 字符串处理

addcslashes — 为字符串里面的部分字符添加反斜线转义字符addslashes — 用指定的方式对字符串里面的字符进行转义bin2hex — 将二进制数据转换成十六进制表示chop — rtrim() 的别名函数chr — 返回一个字符的ASCII码chunk_split — 按一定的字符长度将字符串分割成小块conve…

使用前端框架Foundation 4来帮助简化响应式设计开发

日期&#xff1a;2013-3-12 来源&#xff1a;GBin1.com Foundation是一套使用广泛的前端开发套件&#xff0c;可以帮助你快速的网站。最近ZURB发布了一个新版本的Foundation 4前端框架&#xff0c;能够有效的帮助你快速的开发响应式的网站。 和另外一个套知名的前端框架BootSt…

C++网络编程快速入门(二):Linux下使用select演示简单服务端程序

目录select参数解释select使用规范select使用缺点基本流程实例代码通信效果演示往期文章select参数解释 extern int select (int __nfds, fd_set *__restrict __readfds,fd_set *__restrict __writefds,fd_set *__restrict __exceptfds,struct timeval *__restrict __timeout)…

Android转载一:Android文件命名规范

REF&#xff1a;http://blog.csdn.net/gulianchao/article/details/23391651 (一) Layout命名 1&#xff0e;contentview命名&#xff1a;activity_功能模块.xml 例如&#xff1a;activity_main.xml、activity_more.xml 2&#xff0e;Dialog命名&#xff1a;dialog_描述.xml …

[转]XBRL应用软件分类

1) 分类标准编辑软件(Taxonomy editor)&#xff1a; 分类标准是XBRL技术的应用基础&#xff0c;每一个采用XBRL技术的国家都必须先按各国的GAAP制订XBRL分类标准&#xff0c;上市公司才能据以编制实例文件。由于一套XBRL 2.0或2.1版分类标准必须包含至少一份XML Schema文…