使用 std::thread 时需要包含 #include<thread> 头文件,定义了表示线程的类、用于互斥访问的类与方法等。
参考网址:
- https://blog.csdn.net/liuker888/article/details/46848905
- https://blog.csdn.net/fengbingchun/article/details/73393229
成员类型和成员函数:
std::thread中主要声明三类函数:(1)、构造函数、拷贝构造函数(拷贝构造函数被禁用,意味着thread不可被拷贝构造,但能被转移(move)或者互换(swap))及析构函数;(2)、成员函数;(3)、静态成员函数(hardware_concurrency,检测硬件并发特性。
构造函数如下:
一些相关的数据结构和存储位置:
//栈上 thread t1(show); //根据函数初始化执行 thread t2(show); thread t3(show); //线程数组 thread th[3]{thread(show), thread(show), thread(show)}; //堆上 thread *pt1(new thread(show)); thread *pt2(new thread(show)); thread *pt3(new thread(show)); //线程指针数组 thread *pth(new thread[3]{thread(show), thread(show), thread(show)});
线程初始化(如下实现了多线程传递参数)
void show(const char *str, const int id); int main() { thread t1(show, "hello!", 0); //三个参数分别为函数名,以及其两个参数 thread t2(show, "C++!", 1); return 0; }
join:调用该函数会阻塞当前线程。阻塞调用者(caller)所在的线程直至被join的std::thread对象标识的线程执行结束;
detach:将当前线程对象所代表的执行实例与该线程对象分离,使得线程的执行可以单独进行。一旦线程执行完毕,它所分配的资源将会被释放。
- 在任何一个时间点上,线程是可结合的(joinable),或者是分离的(detached)。一个可结合的线程能够被其他线程收回其资源和杀死;在被其他线程回收之前,它的存储器资源(如栈)是不释放的。相反,一个分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放。
- threads.joinable() 判断线程是否可以join ;threads.join();//主线程等待当前线程执行完成再退出 ; th.detach();
//脱离主线程的绑定,主线程挂了,子线程不报错,子线程执行完自动退出。 //detach以后,子线程会成为孤儿线程,线程之间将无法通信。
---------------------------------
获取CPU核心个数:
n = thread::hardware_concurrency();//获取cpu核心个数
原子变量与线程安全:线程之间会有冲突(下面的代码可能存在num++重叠的现象)
- 互斥量:
#include<iostream> #include<thread> #include<mutex> using namespace std; const int N = 100000000; int num(0); mutex m; void run() { for (int i = 0; i < N; i++) { m.lock(); num++; m.unlock(); } } int main() { clock_t start = clock(); thread t1(run); thread t2(run); t1.join(); t2.join(); clock_t end = clock(); cout << "num=" << num << ",用时 " << end - start << " ms" << endl; return 0; }
存在问题:计算速度很慢,原因主要是互斥量加解锁需要时间 。std::mutex。
- 原子变量:
#include<iostream>
#include<thread>
#include<atomic>
using namespace std;
const int N = 100000000;
atomic_int num{ 0 };//不会发生线程冲突,线程安全
void run()
{
for (int i = 0; i < N; i++)
{
num++;
}
}
int main()
{
clock_t start = clock();
thread t1(run);
thread t2(run);
t1.join();
t2.join();
clock_t end = clock();
cout << "num=" << num << ",用时 " << end - start << " ms" << endl;
return 0;
}
通过原子变量后运算结果正确,计算速度一般。参考std::atomic
但其实只要使用join,可以提升计算的速度
thread t1(run); t1.join(); //结束才回到主线程 thread t2(run); t2.join();
------------------------
时间等待的问题
#include<iostream> #include<thread> #include<chrono> using namespace std; int main() { thread th1([]() { //让线程等待3秒 this_thread::sleep_for(chrono::seconds(3)); //让cpu执行其他空闲的线程 this_thread::yield(); //线程id cout << this_thread::get_id() << endl; }); return 0; }
- yield()函数可以用来将调用者线程跳出运行状态,重新交给操作系统进行调度,即当前线程放弃执行,操作系统调度另一线程继续执行;
- sleep_until()函数是将线程休眠至某个指定的时刻(time point),该线程才被重新唤醒;
- sleep_for()函数是将线程休眠某个指定的时间片(time span),该线程才被重新唤醒,不过由于线程调度等原因,实际休眠实际可能比sleep_duration所表示的时间片更长。
-------------------------------
线程的交换使用 swap(t1, t2);
线程移动使用thread t2 = move(t1);