目录

  • 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++多线程快速入门(二)共享数据同步以及数据竞争相关推荐

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

    目录 设计思路 主线程运行逻辑 task以及taskpool设计 详细流程讲解 完整代码 打印结果 往期回顾 设计思路 线程池实际上就是一组线程,当我们需要异步执行一些任务时,经常要通过OS频繁创建和 ...

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

    互斥锁完成 #include <iostream> #include <deque> #include <thread> #include <mutex> ...

  3. Java 高级 --- 多线程快速入门

    这世上有三样东西是别人抢不走的:一是吃进胃里的食物,二是藏在心中的梦想,三是读进大脑的书 多线程快速入门 1.线程与进程区别 每个正在系统上运行的程序都是一个进程.每个进程包含一到多个线程.线程是一组 ...

  4. AS3多线程快速入门(三):NAPE物理引擎+Starling

    原文:http://blog.domlib.com/articles/345 [更新]Adobe在11.4正式发布的最后一刻移除了ByteArray.shareable功能的支持,推迟到11.5版本再 ...

  5. AS3多线程快速入门(三):NAPE物理引擎+Starling[译]

    原文链接:http://esdot.ca/site/2012/intro-to-as3-workers-part-3-nape-physics-starling [更新]Adobe在11.4正式发布的 ...

  6. C++多线程快速入门(一):基本常用操作

    目录 case1:创建线程1 join.detach case2:创建线程2 线程传参 传值或者传引用 case3:创建线程 线程传参 functional object作为参数 case4:观察多线 ...

  7. Python3快速入门(十四)——Pandas数据读取

    Python3快速入门(十四)--Pandas数据读取 一.DataFrame IO 1.CSV文件 pandas.read_csv(filepath_or_buffer, na_values='NA ...

  8. 【Python零基础快速入门系列 | 07】浪漫的数据容器:成双成对之字典

    这是机器未来的第11篇文章 原文首发链接:https://blog.csdn.net/RobotFutures/article/details/125038890 <Python零基础快速入门系 ...

  9. Java 多线程快速入门(面试概念解答一)

    Java 多线程快速入门 什么是进程,什么是线程,什么是多线程? 创建多线程有哪些方式? 启动线程是使用调用start方法还是run方法? 获取线程对象以及名称 守护线程 使用setDaemon(tr ...

最新文章

  1. unity 游戏第一次安装完之后运行,切出来,点击桌面图标后黑屏问题
  2. 【错误记录】Flutter 界面跳转报错 ( Navigator operation requested with a context that does not include a Naviga )
  3. 5个很常用的CSS3网页小实例
  4. 【小白学习PyTorch教程】十五、BERT:通过PyTorch来创建一个文本分类的Bert模型
  5. 感想总结——热烈庆祝CSDN博客排名进入前20000名
  6. 顺序三元组 java_hihocoder-1550-顺序三元组
  7. cuSPARSE库:(十七)cusparseStatus_t 返回信息
  8. 文学系列:《叶之震颤》读书笔记
  9. php点击表格单元格链接,详解PhpSpreadsheet单元格设置样式、图片、超链接等
  10. PyQt5保姆级教程-- 从入门到精通
  11. python最小二乘法求a b_最小二乘法公式推导及Python实现
  12. 道一MD5校验工具发布
  13. Adobe pr,ae,ps...软件的安装,及简单的使用
  14. 看英语数据手册很难?5步帮你搞定!
  15. 联通手机卡网速的修改
  16. 微信摇心愿如何选不同服务器,2020微信游戏摇心愿活动参与方法介绍
  17. Qt creator开发的C++应用程序运行崩溃,异常代码0xc0000409,错误偏移量0x0009efbb解决。
  18. c语言的论文,C语言论文
  19. FaceNet 人脸比对框架 部署+测试
  20. 钉钉API考勤打卡记录获取并存入数据库(python)

热门文章

  1. 基于nbu oj c语言答案,Just oj 2018 C语言程序设计竞赛(高级组)F:Star(结构体排序+最小生成树)...
  2. JSP+Tomcat+SQL Server 2000+JDBC实现合同信息管理系统
  3. 教你玩转CSS 伪类
  4. Shiro-550反序列化漏洞复现
  5. php html邮件,php发送HTML邮件
  6. matlab短均线滞后项,均线理论的滞后性问题
  7. php制图汉字,PHP用imageTtfText函数在图片上写入汉字
  8. 什么是URL转发和一个IP建多个Web站点--主机头名法
  9. js将canvas保存成图片并下载
  10. 插件开发-UI插件开发