一、thread 线程
c++11中thread join和detach的区别:https://blog.csdn.net/c_base_jin/article/details/79233705
c++11 使用detach()时,主线程和孤儿detach线程的同步控制:https://blog.csdn.net/trouble_provider/article/details/85268764
定义对象thread t1(线程函数名,参数名,参数名,...); //线程对象一被定义就会开始运行;
讲两个必要的函数:join()和detach()
t1.join();join()是一个阻塞函数。主线程和子线程之间是同步的关系,即主线程要等待子线程执行完毕才会继续向下执行。
detach();此时 子线程和main thread 完全分离,两个线程自顾自的运行,main thread可以不等子线程运行完,就提前结束。但是一旦main thread结束了,子线程也会被销毁;
C++11中引入了多线程技术,通过thread线程类对象来管理线程,只需要#include <thread>即可。thread类对象的创建意味着一个线程的开始。
假设定义一个名为first的线程:
thread first(线程函数名,参数1,参数2,......); //每个线程有一个线程函数,线程要做的事情就写在线程函数中。
C++中一个标准线程函数只能返回void,因此需要从线程中返回值往往采用传递引用的方法。我们讲,传递引用相当于扩充了变量的作用域。
================================================
二、mutex 锁
c/c++ 多线程 mutex的理解:https://www.cnblogs.com/xiaoshiwang/p/9880228.html
C++11 并发指南三(std::mutex 详解):https://www.cnblogs.com/haippy/p/3237213.html
c++多线程编程互斥锁初步:https://www.cnblogs.com/shaonianpi/p/11434148.html
C++读写锁:https://blog.csdn.net/u014805066/article/details/60755567
定义mutex m;
给mutex上锁: 在函数中调用m.lock();
如果其他线程要调用该函数,由于处于上锁状态,就阻塞在那里。必须等待锁打开后,其他线程才能进去;
给mutex解锁,使用m.unlock();
用哪个mutex上锁就得用哪个mutex解锁;
但是一般来说不直接这么用;会使用std::lock_guard或者std::unique_lock模板类,将mutex对象类型作为模板参数;即便发生了异常也会自动解锁。
读写锁适合于对数据结构的读次数比写次数多得多的情况. 因为, 读模式锁定时可以共享, 以写模式锁住时意味着独占, 所以读写锁又叫共享-独占锁。
================================================
三、condition_variable
C++11并行编程-条件变量(condition_variable)详细说明:https://www.cnblogs.com/GuoXinxin/p/11675053.html
当 std::condition_variable对象的某个wait 函数被调用的时候,它使用 std::unique_lock(通过 std::mutex) 来锁住当前线程。
在线程被堵塞时,该函数会自己主动调用 lck.unlock() 释放锁,使得其它被堵塞在锁竞争上的线程得以继续运行。
另外,一旦当前线程获得通知(notified,一般是另外某个线程调用 notify_* 唤醒了当前线程),wait()函数也是自己主动调用 lck.lock(),使得lck的状态和 wait 函数被调用时同样。主动调用 lck.lock()时如果别人获得锁了,则进入锁竞争当中。
================================================
四、std::模板类,或者装饰器
C++11并发——多线程lock_gurad ,unique_lock (三):https://www.cnblogs.com/xiangtingshen/p/10538785.html
[c++11]多线程编程(五)——unique_lock:https://www.jianshu.com/p/34d219380d90
多线程 unique_lock的使用:https://www.cnblogs.com/xiaoshiwang/archive/2018/11/05/9912004.html
lock_guard (在构造函数里加锁,在析构函数里解锁)
unique_lock 自动加锁、解锁;还可以临时加锁、解锁;
std::ref(v):
如果线程函数的某个参数是一个引用;那么我们在主线程生成一个线程对象,并初始化线程函数,参数时。
不是直接把v传递给线程对象的构造函数中。而是使用std::ref(v);反正这样做可以保证传递给线程函数的参数是v的引用。
std::ref用于包装按照引用传递的值;
std::ref()和&:https://www.jianshu.com/p/277675675593
================================================
五、线程间通信
最常规的全局变量方式
这是我们线程间通讯最常规的办法,因为全局变量的存储位置位于data段,没有存在于函数栈中,程序的其他函数都可以访问。
处于这个条件,各个线程函数都可以操作全局变量,达到数据传递的问题。不过由于现代CPU的时间片轮转线程抢占机制,全局变量的操作需要注意同步的问题。
关于线程同步的问题,锁机制实现了一部分功能,但是由于编译器的优化,还是有可能出现同步问题。
我们建议使用volatile 修饰符,它告诉编译器无需对该变量作任何的优化,即无需将它放到一个寄存器中,并且该值可被外部改变。(保留url)
使用自定义消息 //消息队列
我们可以在一个线程的执行函数中向另一个线程发送自定义的消息来达到通信的目的。
一个线程向另外一个线程发送消息是通过操作系统实现的。
利用Windows操作系统的消息驱动机制,当一个线程发出一条消息时,操作系统首先接收到该消息,
然后把该消息转发给目标线程,接收消息的线程必须已经建立了消息循环。
std::promise 可以用来在线程间提供数据传递。
std::future = std::promise.get_future()。
线程中可以对promise赋值std::promise.set_value。
赋值之后std::future.get()就会返回其他线程中设置的值
std::packaged_task 可以包裹一个函数, 有点类似std::function,不同之处在于这个可以通过get_future返回std::future对象来获取异步执行的函数结果。
同步
互斥锁、读写锁
条件变量
信号量 //C++11中没有予以实现
C++ 多线程之间的通信方式(windows下实现):https://blog.csdn.net/lizhenwei0219/article/details/96145663
c++ 线程间通信方式:https://www.cnblogs.com/jobs1/p/10784021.html
c++11信号量实现:https://blog.csdn.net/zdarks/article/details/46994767
================================================
六、线程池:
图解线程池原理与C++实现:https://blog.csdn.net/yu876876/article/details/81608202
基于C++11实现线程池的工作原理:https://www.cnblogs.com/ailumiyana/p/10016965.html
C++线程池:https://www.cnblogs.com/smartNeo/p/11489085.html
================================================
七、死锁:
c++11多线程记录4:死锁:https://www.cnblogs.com/ChenLambda/p/11728570.html
可重入锁与不可重入锁以及常见的死锁现象:https://blog.csdn.net/u010275850/article/details/100110450
[c++11]多线程编程(四)——死锁(Dead Lock):https://segmentfault.com/a/1190000016217199
线程同步之利器(1)——可递归锁与非递归锁:https://blog.csdn.net/zouxinfox/article/details/5838861
================================================
参考链接: