std::thread
头文件引入#include <thread>
,创建线程thread th1(func);
,主要了解一下两个函数;
join()
:可以调整阻塞态位置,个人理解,如果创建了线程,立马用join
纯属脱裤子那啥,和直接调用函数没区别,主线程照样阻塞,阻塞主线程,等待子线程结束后再结束,不执行后续程序。
detach()
:主线程为主,将子线程和主线程的关联分离,管你线程在干嘛,主线程结束下班休息。
std::lock_guard、std::unique_lock
资源获取及初始化(RAII)
,lock_guard
是个模板类,会在构造函数中初始化信号量,会在析构函数中解锁资源,避免死锁情况。使用方法为lock_guard<mutex> lock(信号量)
unique_lock
和前者使用方法相同,同属模板类,区别为:前者不够灵活,创建的对象只有超出作用域时,对象被析构才能释放这个锁;后者又更多的函数供使用,可以提前对锁进行操作;
std::mutex
互斥量,头文件引用#inclcude <mutex>
,mutex m;
然后使用lock
和unlock
函数来上锁和解锁,通过上锁和解锁来避免和解决多线程不安全的问题。
原子操作
有文件引入#include <atomic>
,可以理解为信号量和锁的封装使用,可以自动帮我们完成一些上锁和解锁的操作。
条件变量
头文件#include <condition_variable>
,定义为condition_variable cv;
常用的是 wait()
和notify_one()
两个成员函数,前者是等待,生效后将阻塞线程进行,等待被后者这个函数唤醒,notify_one()
是唤醒其中一个wait()
,与之相对应的还有notify_all()
可以唤醒所有等待线程。
信号量
这个是在c++20
之后才支持的,要注意编译器版本,头文件引入#include <semaphore>
,常用模板类counting_semaphore
(初始化需要赋初值counting_semaphore<5> cs(0)
;其中5
是我自己瞎写的表示一次可以被唤醒的线程个数上限。)的模板特化为binary_semaphore
(counting_semaphore
上限为1
的情况) 其中常用的成员函数有release和acquire 。
a. semaphore release == condition_variable notify
b. semaphore acquire == condition_variable wait