thread_local变量在每个线程第一次执行到时初始化(类似static),并在每个线程各自累加,并在线程结束时释放。

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

async:能够保留线程的返回值。启动一个线程,或在期望等待时同步任务.
std::launch::async表明函数必须在其所在的独立线程上执行
std::launch::defered表明函数调用被延迟到wait()或get()函数调用时才执行
如果两者都行,取决于实现;未声明则未定义。

####################
线程相关的很多=默认是move语义。
thread:.join(), .detach(), .swap()
mutex:mutex, lock_guard, unique_lock等, .lock(), .unlock()
condition_variable:.notify_one(), .wait()//实现等待队列
future:
async: 类似于thread, 能保留返回值,可启动一个线程,或在期望等待时同步任务.
    std::launch::async表明函数必须在其所在的独立线程上执行
    std::launch::defered表明函数调用被延迟到wait()或get()函数调用时才执行
    如果两者都行,取决于实现;未声明则未定义。
packaged_task: 构造时绑定一个函数对象,.get_future()将返回值绑定到future,再执行task函数(或传递到std::thread对象中可作为线程函数)
promise: .getfuture(), 绑定到future; 执行.set_value()后, 绑定的future可.get(), 否则.get()一直被阻塞直到.set_value()执行。
future: .share(), .wait(), .get()
    当future的状态还不是就绪时就调用绑定的promise, packaged_task等的析构函数,会在期望里存储一个异常。
    std::future有局限性,在很多线程等待时,只有一个线程能获取等待结果。
    当多个线程需要等待相同的事件的结果,需要用shared_future来替代future。
    shared_future与future类似,但shared_future可以拷贝、多个shared_future可以共享某个共享状态的最终结果(即共享状态的某个值或者异常)。
    shared_future可通过某个future对象隐式转换,或通过future::share()显示转换,无论哪种转换,被转换的那个future对象都会变为not-valid.

atomic:
  is_lock_free: 如果某个对象满足 lock-free 特性,在多个线程访问该对象时不会导致线程阻塞。
        (其实看我们那副图就是说你的各个线程不会互相阻塞,
        那么你的程序才能成为lock free的。
        像我们平常用的互斥锁,当有线程获得锁,
        其他线程就被阻塞掉了,
        这里的问题就是如果获得锁的线程挂掉了,
        而且锁也没有释放,那么整个程序其实就被block在那了,
        而如果程序是lock free的那么即使有线程挂掉,
        也不影响整个程序继续向下进行,
        也就是系统在整体上而言是一直前进的。
        大概系统内部自有一套判断机制)
  store: 修改被封装的值
  load: 读取被封装的值

内存模型:
  要想写出高性能的多线程程序必须理解内存模型,
  因为编译器会给你的程序做优化(如指令重排等),
  CPU为了提升性能也有多发射和乱序执行,
  因此程序在最终执行时并不会按照你之前的原始代码顺序来执行,
  所以内存模型是程序员、编译器,CPU 之间的契约,遵守契约后大家就各自做优化,从而尽可能提高程序的性能。
  _relaxed: 不对执行顺序做任何保证
  _acquire: 本线程中,所有后续的读操作必须在本原子操作完成后执行
  _release: 本线程中,所有之前的写操作完成后才能执行本原子操作
  _acq_rel: 同时包含acquire和release
  _consume: 本线程中,所有后续的有关本原子类型的操作,必须在本原子操作完成后执行
  _seq_cst: 全部存取按顺序执行

=========================================================

PV原语: 信号量s, 除一个整数值s.cound, 还有一个进程等待队列s.queue, 是阻塞在该信号上的进程。

信号量的值为非负值表示当前空闲资源数, 负值表示当前阻塞在该信号上的进程。

P(Semaphore s) {--s.count; if(s.count < 0) 阻塞调用进程;}

V(Semaphore s) {++s.count; if(s.count <= 0) 唤醒某一进程;}

互斥量mutex就是count = 1的PV原语。

如何实现同步?考虑进程的DAG图, A进程的某个节点a有指向B进程的某个节点b, 那么相当于一开始b处于阻塞态, A进程到a处执行V原语释放资源。如公交司机开车停车与售票员开门关门。

经典算法

生产者与消费者:(以下代码每个生产者生产数量与每个消费者消费数量相同)

 /***************
首先你要有一个生产者和消费者公用的Buffer, 它要求用mutex和condition variable来实现锁
一个互斥量, 互斥地访问buffer, 多个消费者和生产者每个消费和生产的数量相同。
本写法本质为单消费者单生产者。
正确写法:
单生产者单消费者: 设置一个互斥量mtx, 互斥地访问buffer; 两个条件变量表示buffer满或空
多生产者单消费者: 再规定总生产量为count_produce, 多生产者互斥地访问count_produce
多生产者单消费者: 再规定总消费量为count_consume, 多消费者互斥地访问count_consume
多生产者单消费者: 再规定总生产量为count_produce, 多生产者互斥地访问count_produce, 规定总消费量为count_consume(count_consume = count_produce), 多消费者互斥地访问count_consume
***************/
#include <bits/stdc++.h>
struct BoundedBuffer {
int* buffer;
int capacity; int front;
int rear;
int count; std::mutex lock; std::condition_variable not_full;
std::condition_variable not_empty; BoundedBuffer(int capacity) : capacity(capacity), front(), rear(), count() {
buffer = new int[capacity];
}
~BoundedBuffer(){
delete[] buffer;
}
void deposit(int data){
std::unique_lock<std::mutex> l(lock);
not_full.wait(l, [this](){return count != capacity; });
buffer[rear] = data;
rear = (rear + ) % capacity;
++count;
not_empty.notify_one();
}
int fetch(){
std::unique_lock<std::mutex> l(lock);
not_empty.wait(l, [this](){return count != ; });
int result = buffer[front];
front = (front + ) % capacity;
--count;
not_full.notify_one();
return result;
}
}; void consumer(int id, BoundedBuffer& buffer){
for(int i = ; i < ; ++i){
int value = buffer.fetch();
std::cout << "Consumer " << id << " fetched " << value << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds());
}
} void producer(int id, BoundedBuffer& buffer){
for(int i = ; i < ; ++i){
buffer.deposit(i);
std::cout << "Produced " << id << " produced " << i << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds());
}
} int main(){
BoundedBuffer buffer(); std::thread c1(consumer, , std::ref(buffer));
std::thread c2(consumer, , std::ref(buffer));
std::thread c3(consumer, , std::ref(buffer));
std::thread p1(producer, , std::ref(buffer));
std::thread p2(producer, , std::ref(buffer)); c1.join();
c2.join();
c3.join();
p1.join();
p2.join(); return ;
}

参考链接

读者写者问题: 参考链接

哲学家进餐问题: 1.最多允许四个人同时在进餐 2.当两边筷子都可用时再去拿 3.每次先拿奇数号的筷子再拿偶数号的筷子 4.分成三种状态, 思考, 饥饿, 进餐, 并且一次拿一双

C++11并发编程个人小结的更多相关文章

  1. C++11 并发编程库

    C++11 并发编程 C++11 新标准中引入了几个头文件来支持多线程编程,他们分别是: <atomic>:该头文主要声明了两个类, std::atomic 和 std::atomic_f ...

  2. C++11 并发编程基础(一):并发、并行与C++多线程

    正文 C++11标准在标准库中为多线程提供了组件,这意味着使用C++编写与平台无关的多线程程序成为可能,而C++程序的可移植性也得到了有力的保证.另外,并发编程可提高应用的性能,这对对性能锱铢必较的C ...

  3. C++11并发编程:多线程std::thread

    一:概述 C++11引入了thread类,大大降低了多线程使用的复杂度,原先使用多线程只能用系统的API,无法解决跨平台问题,一套代码平台移植,对应多线程代码也必须要修改.现在在C++11中只需使用语 ...

  4. C++11并发编程:原子操作atomic

    一:概述 项目中经常用遇到多线程操作共享数据问题,常用的处理方式是对共享数据进行加锁,如果多线程操作共享变量也同样采用这种方式. 为什么要对共享变量加锁或使用原子操作?如两个线程操作同一变量过程中,一 ...

  5. C++11并发编程:async,future,packaged_task,promise

    一:async std::async:用于创建异步任务,可以代替创建线程,函数原型:async(std::launch::async | std::launch::deferred, f, args. ...

  6. C++11并发编程1------并发介绍

    也许有人会觉得多线程和并发难用,复杂,还会让代码出现各种各样的问题,不过,其实它是一个强有力的工具,能让程序充分利用硬件资源,让程序运行得更快. 何谓并发: 两个或更多独立得活动同时发生.计算机中就是 ...

  7. C++11并发编程实战 免费书籍

    C++11 博客http://www.cnblogs.com/haippy/p/3284540.html 网上推荐的C++多线程基本都是C++ Concurrency in Action 英文版的,中 ...

  8. 11 并发编程-(线程)-信号量&Event&定时器

    1.信号量(本质也是一把锁)Semaphore模块 信号量也是一把锁,可以指定信号量为5,对比互斥锁同一时间只能有一个任务抢到锁去执行, 信号量同一时间可以有5个任务拿到锁去执行, 如果说互斥锁是合租 ...

  9. Windows:C++11并发编程-条件变量(condition_variable)详解

    <condition_variable >头文件主要包含了与条件变量相关的类和函数.相关的类包括 std::condition_variable和 std::condition_varia ...

随机推荐

  1. 配置centos7来支持xshell远程访问和xftp传输文件

    前提: 首先需要一台已装有centos7的电脑(虚拟机的配置这里不说明,这里用的是物理机) 背景: 在工作中访问linux的环境通常需要Xshell等终端软件,通过配置静态IP远程服务器进行管理开发. ...

  2. HTML6的10个高级新特性

    网络技术正趋向于发展为一个巨大的移动APP市场,在Web开发的革命浪潮中起着指示性作用,自HTML引入以来,应用程序变得So easy,web开发中运用先进技术也很容易处理各种复杂Bug. 作为专业的 ...

  3. javascript实现对html便签等字符的转义

    参考链接:https://www.jb51.net/article/152700.htm 请访问以上链接. 本人纯搬迁,防止原作者删除. <script> var HtmlUtil = { ...

  4. Docker 入门之docker容器创建

    使用docker容器的大多数人都是因为想要隔离不同运行环境的差异,使得自己的应用能更好的移植和部署.那么我们来看看掌握docker需要掌握哪些方面. 1,搭建docker环境 2,编译镜像并将其运行成 ...

  5. shutdown命令详解

    基础命令学习目录 原文链接:http://www.cnblogs.com/qlqwjy/p/7746364.html 我 们在操作Linux v/服务器的时候肯定会有需要重启系统,或者关闭系统等操作. ...

  6. BugPhobia准备篇章:Beta阶段前后端接口文档

    0x00:序言 Two strangers fell in love, Only one knows it wasn’t by chance. To the searching tags, you m ...

  7. 20172321 2017-2018-2《Java程序设计》第三周学习总结

    20172321 2017-2018-2<Java程序设计>第三周学习总结 教材学习内容总结 第三章要点: 要点1 :String类.Random类.Math类和枚举型,这几个是很有用的并 ...

  8. spring冲刺第七天

    昨天进行地图和人物的代码整合,有所缺陷. 今天使人物成功的在地图上运动,并设计炸弹爆炸效果. 遇到的问题:炸弹不会吧人物炸死,只会炸没砖块.

  9. 我是一名IT小小鸟

    我是一只it小小鸟 书中介绍了it界大牛们大学期间的学习方法和对未来的职业规划,相比他们,自我感觉相距甚远,对这学科的热情程度也远远比不上他们. 就拿目前数据结构这门高深的课程,应通过更多的课外扩展来 ...

  10. 福州大学软工1816 K 班助教总结

    春节时期总有各种诱惑因素(例如路人超能第二季),拖到现在才发布十分抱歉orz. 一.感谢 首先对柯老师和软工助教指导团队这一学期以来的支持和指导表示感谢.第一次做助教,有时候会提出一些不大成熟的想法, ...