线程


  • std::thread

  1. 创建std::thread,一般会绑定一个底层的线程。若该thread还绑定好函数对象,则即刻将该函数运行于thread的底层线程。
  2. 线程相关的很多默认是move语义,因为在常识中线程复制是很奇怪的行为。
  3. joinable():是否可以阻塞至该thread绑定的底层线程运行完毕(倘若该thread没有绑定底层线程等情况,则不可以join)
  4. join():本线程阻塞直至该thread的底层线程运行完毕。
  5. detach():该thread绑定的底层线程分离出来,任该底层线程继续运行(thread失去对该底层线程的控制)。

互斥变量


为了避免多线程对共享变量的一段操作会发生冲突,引入了互斥体和锁。

  • std::mutex

  1. 互斥体,一般搭配锁使用,也可自己锁住自己(lock(),unlock())。
  2. 若互斥体被第二个锁请求锁住,则第二个锁所在线程被阻塞直至第一个锁解锁。
  • std::lock_guard

  1. 简单锁,构造时请求上锁,释放时解锁,性能耗费较低。适用区域的多线程互斥操作。
  • std::unique_lock

  1. 更多功能也更灵活的锁,随时可解锁或重新锁上(减少锁的粒度),性能耗费比前者高一点点。适用灵活的区域的多线程互斥操作。

原子变量


原子变量的意思就是单个最小的、不可分割的变量(例如一个int),原子操作则指单个极小的操作(例如一个自增操作)

C++的原子类封装了这种数据对象,使多线程对原子变量的访问不会造成竞争。(可以利用原子类可实现无锁设计)

  • std::atomic_flag

  1. 它是一个原子的布尔类型,可支持两种原子操作。(实际上mutex可用atomic_flag实现)
  2. test_and_set(): 如果atomic_flag对象被设置,则返回true; 如果atomic_flag对象未被设置,则设置之,返回false。
  3. clear():清除atomic_flag对象。
  • std::atomic<T>

    1. 对int, char, bool等基本数据类型进行原子性封装(其实是特化模板)。
    2. store():修改被封装的值。
    3. load() 读取被封装的值。

线程独立变量


  • thread_local

  1. 变量在每个线程各自独立(类似static),并在线程结束时释放。

条件变量


条件变量一般是用来实现多个线程的等待队列,即主线程通知(notify)有活干了,则等待队列中的其它线程就会被唤醒,开始干活。

  • std::condition_variable

  1. wait(std::unique_lock<std::mutex>& lock, Predicate pred = [](){return true;}):pred()为true时直接返回,pred()为false时,lock必须满足已被当前线程锁定的前提。执行原子地释放锁定,阻塞当前线程,并将其添加到等待*this的线程列表中。
  2. notify_one()/notify_all():激活某个或者所有等待的线程,被激活的线程重新获得锁。

虚假唤醒:

处于等待的添加变量可以通过notify_one/notify_all进行唤醒,调用函数进行信号的唤醒时,处于等待的条件变量会重新进行互斥锁的竞争。

没有得到互斥锁的线程就会发生等待转移(wait morphing),从等待信号量的队列中转移到等待互斥锁的队列中,一旦获取到互斥锁的所有权就会接着向下执行,

但是此时其他线程已经执行并重置了执行条件(例如一个活只需要两个线程来干,通知完两个线程后重置执行条件),这可能导致该线程执行引发未定义的错误。

//不能应对虚假唤醒
if(pred()){
cv.wait(lock);
}
//利用while重复判断执行条件,可以应对虚假唤醒
while(!pred()){
cv.wait(lock);
}
//C++11提供了更方便的语法,将判断条件作为一个参数,实际上等价于前者
cv.wait(lock,pred);

提供方


  • std::promise<T>

  1. 构造时,产生一个未就绪的共享状态(包含存储的T值和是否就绪的状态)。可设置T值,并让状态变为ready。
  2. get_future():共享状态绑定到future对象。
  3. set_value():设置共享状态的T值,并让状态变为ready,则绑定的future对象可get()。
  • std::packaged_task<Func>

  1. 构造时绑定一个函数对象,也产生一个未就绪的共享状态。通过thread启动或者仿函数形式启动该函数对象。
  2. 但是相比promise,没有提供set_value()公用接口,而是当执行完绑定的函数对象,其执行结果返回值或所抛异常被存储于能通过 std::future 对象访问的共享状态中。
  3. get_future():共享状态绑定到future对象。

获取方


  • std::future<T>

  1. 用于访问共享状态(即获取值)。
  2. 当future的状态还不是ready时就调用一个绑定的promise, packaged_task等的析构函数,会在期望里存储一个异常。
  3. std::future有局限性,在很多线程等待时,只有一个线程能获取等待结果。
  4. share():分享同一个共享状态给另一个future
  5. wait():若共享状态不是ready,则阻塞直至ready。
  6. get():获得共享状态的值,若共享状态不是ready,则阻塞直至ready。
  • std::shared_future<T>

  1. 当需要多个线程等待相同的事件的结果(即多处访问同一个共享状态),需要用std::shared_future来替代std::future。
  2. shared_future与future类似,但shared_future可以拷贝、多个shared_future可以共享某个共享状态的最终结果(即共享状态的某个值或者异常)。
  3. shared_future可通过某个future对象隐式转换,或通过future::share()显示转换,无论哪种转换,被转换的那个future对象都会变为not-valid

异步(封装的异步操作)


  • std::async(std::launch::async | std::launch::deferred, Func, Args...)

  1. 异步执行一个函数,其函数执行完后的返还值绑定给使用std::async的futrue(其实是封装了thread,packged_task的功能,使异步执行一个任务更为方便)。
  2. 若用创建std::thread执行异步行为,硬件底层线程可能不足,产生错误。而std::async将这些底层细节掩盖住,如果使用默认参数则与标准库的线程管理组件一起承担线程创建和销毁、避免过载、负责均衡的责任。
  3. 所以尽量使用以任务为驱动的async操作设计,而不是以线程为驱动的thread设计。
  4. std::async中的第一个参数是启动策略,它控制std::async的异步行为,我们可以用三种不同的启动策略来创建std::async:

           std::launch::async参数 保证异步行为,即传递函数将在单独的线程中执行。

           std::launch::deferred参数 当其他线程调用get()/wait()来访问共享状态时,将调用非异步行为。

           std::launch::async | std::launch::deferred参数 是默认行为。有了这个启动策略,它可以异步运行或不运行,这取决于系统的负载。

///使用示例
std::future<std::string> resultFromDB = std::async(std::launch::async, fetchDataFromDB, "Data1");
std::string data1 = resultDromDB.get();

C++11 (多线程)并发编程总结的更多相关文章

  1. Java 多线程并发编程一览笔录

    Java 多线程并发编程一览笔录 知识体系图: 1.线程是什么? 线程是进程中独立运行的子任务. 2.创建线程的方式 方式一:将类声明为 Thread 的子类.该子类应重写 Thread 类的 run ...

  2. C++11 之 并发编程 (一)

    未来芯片制造,如果突破不了 5nm 极限,则 CPU 性能的提升,可能会依赖于三维集成技术,将多个 CPU 核集成在一起,使得多核系统越来越普遍. 以前的 C++ 多线程,一是受限于平台,多借助于封装 ...

  3. Java基础系列篇:JAVA多线程 并发编程

    一:为什么要用多线程: 我相信所有的东西都是以实际使用价值而去学习的,没有实际价值的学习,学了没用,没用就不会学的好. 多线程也是一样,以前学习java并没有觉得多线程有多了不起,不用多线程我一样可以 ...

  4. Java 多线程并发编程

    导读 创作不易,禁止转载! 并发编程简介 发展历程 早起计算机,从头到尾执行一个程序,这样就严重造成资源的浪费.然后操作系统就出现了,计算机能运行多个程序,不同的程序在不同的单独的进程中运行,一个进程 ...

  5. 【收藏】Java多线程/并发编程大合集

    (一).[Java并发编程]并发编程大合集-兰亭风雨    [Java并发编程]实现多线程的两种方法    [Java并发编程]线程的中断    [Java并发编程]正确挂起.恢复.终止线程    [ ...

  6. java多线程并发编程与CPU时钟分配小议

    我们先来研究下JAVA的多线程的并发编程和CPU时钟振荡的关系吧 老规矩,先科普 我们的操作系统在DOS以前都是单任务的 什么是单任务呢?就是一次只能做一件事 你复制文件的时候,就不能重命名了 那么现 ...

  7. java多线程并发编程

    Executor框架 Executor框架是指java 5中引入的一系列并发库中与executor相关的一些功能类,其中包括线程池,Executor,Executors,ExecutorService ...

  8. Java 多线程并发编程面试笔录一览

    知识体系图: 1.线程是什么? 线程是进程中独立运行的子任务. 2.创建线程的方式 方式一:将类声明为 Thread 的子类.该子类应重写 Thread 类的 run 方法 方式二:声明实现 Runn ...

  9. 11 go并发编程-上

    其他编程语言并发编程的效果 并发编程可以让开发者实现并行的算法以及编写充分利用多核处理器和多核性能的程序.在当前大部分主流的编程语言里,如C,C++,java等,编写维护和调试并发程序相比单线程程序而 ...

随机推荐

  1. C++类中静态变量和普通变量的区别

    静态变量: 1.静态变量会被编到程序的exe里面,从程序启动到结束,它一直存在: 2.静态变量的初始化值为0: 3.全局变量默认是静态变量: 4.在类中的函数变量前面加了static的也是静态变量,只 ...

  2. 【环套树+树形dp】Bzoj1040 [ZJOI2008] 骑士

    Description Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战火 ...

  3. BZOJ_1485_[HNOI2009]有趣的数列_卡特兰数

    BZOJ_1485_[HNOI2009]有趣的数列_卡特兰数 Description 我们称一个长度为2n的数列是有趣的,当且仅当该数列满足以下三个条件: (1)它是从1到2n共2n个整数的一个排列{ ...

  4. Jmeter-----【mac电脑】配置web浏览器的代理抓取请求

    在测试中,不仅会涉及到APP中的数据测试,时常我们APP的数据需要与后台进行交互,因此我们不可避免的也需要对web进行接口测试,更准确的来说是使用web的接口来快速的帮我们实现App中所需的数据录入, ...

  5. TensorFlow TensorBoard使用

    摘要: 1.代码例子 2.主要功能内容: 1.代码例子 <TensorFlow实战>使用MLP处理Mnist数据集并TensorBoard上显示 2.主要功能 执行TensorBoard程 ...

  6. pyqt5将图片插入面板

    from PyQt5.QtWidgets import * from PyQt5 import QtCore,QtWidgets from PyQt5.QtGui import * import sy ...

  7. 实时监听input输入框value的变化:

    HTML5 标准事件 oninput 和 IE 专属事件 onpropertychange 事件实时监听输入框value的变化 oninput 事件在用户输入时触发. 该事件在 <input&g ...

  8. python中报错"json.decoder.JSONDecodeError: Expecting value:"的解决

    在学习python语言中用json库解析网络数据时,我遇到了两个编译错误:json.decoder.JSONDecodeError: Expecting property name enclosed ...

  9. CentOS 本地和网络yum源简单说明及配置

    1.简述 Yellow dog Updater, Modified由Duke University团队,修改Yellow Dog Linux的Yellow Dog Updater开发而成,是一个基于R ...

  10. elasticsearch6.6.2在Centos6.9的安装

    JDK8 做个记录,以防以后忘记能够查看. 1.elastic是java编写的,先搭建运行环境,6.6.2版本必须要jdk8以上版本才可运行,先官网下载jdk,上传服务器 https://www.or ...