好久不写博客了,一方面是觉得比较花时间,另一方面觉得也没啥好写的,不过最近看cppreference上关于c++多线程的支持,觉得有必要整理整理,就来写一写好了。
一、基本的多线程需要的东西:
对于多线程代码而言,我觉得最基本需要有以下一些类型:
thread类型用来跟踪管理一个线程,互斥锁提供多个线程共享资源的安全访问机制,条件变量可以使得多个协同线程按顺序访问共享资源,减小CPU资源损耗。对于以上几种基本类型,c++都提供了对应的类型支持,分别是:
二、thread
该类型在头文件thread中定义,包含于std命名空间:
#include
1、创建线程:
c++支持任何可以像函数一样被调用的对象作为线程的入口函数,具体为:
#include
#include
void function_default()
{
std::cout<<"This is function_default.\n";
}
void function_para1(int x)
{
std::cout<<"This is function with one para: "<<x<<std::endl;
}
class AAA
{
public:
void operator()(int x) const{
std::cout<<"This is an object of AAA: "<<x<<std::endl;
}
};
int main()
{
std::thread t1(function_default);
std::thread t2(function_para1,10);
AAA obj;
std::thread t3(obj,20);
t1.join();
t2.join();
t3.join();
return 0;
}
2、线程对象创建机制:
c++线程对象在构造时,先将传入的参数赋值到新线程的独立空间中,然后此时原线程将继续向下执行,新线程在自己的空间中自动执行。
void func(int& x){
...
}
int main(){
int p=10;
std::thread t1(func,std::ref(p));
...
}
void func_thread(std::string str){
...
}
std::thread func(){
char a[]="This is a string";
return std::thread(func_thread,a);
}
在函数func中用a数组作为参数创建线程并返回,线程构造函数首先将a的地址赋值到线程空间,然后func将返回,此时a的空间以不合法,然而线程需要访问a的空间以构造str,此时的行为是未知的,解决方法是传参时完成类型转换:
std::thread func(){
char a[]="This is a string";
return std::thread(func_thread,std::string(a));
}
3、线程对象的性质
void function_default()
{
while(1)
std::cout<<"This is function_default.\n";
}
void function_para1(int x)
{
while(1)
std::cout<<"This is function with one para: "<<x<<std::endl;
}
int main()
{
std::thread t1(function_default);
std::thread t2(function_para1,10);
std::thread t3=std::move(t1);
//t2=std::move(t1) 运行时报错
t1.join();
t3.join();
//因为t2将线程所有权转交给了t3,所以t2不用join了,其joinable()为false,也不具备任何线程的所有权,空壳。
return 0;
}
4、线程的自动join
在c++标准中,一个线程若为joinable的,则必须在线程对象被销毁前join它,无论是正常退出定义域还是异常退出都需要这么做,所以最好可以使用一个管理类对其封装。
貌似c++没有为thread提供类似的功能,c++20新增的jthread貌似提供了这种功能,但在我的机器上g++ 7.4.0没有提供类似的支持貌似。但这里可以自己写一个封装类进行管理。
class unique_thread
{
std::thread p;
public:
explicit unique_thread(std::thread&& t):p(std::move(t)){}
explicit unique_thread(unique_thread&& t):p(std::move(t.p)){}
unique_thread& operator=(unique_thread&& t)
{
if(p.joinable())
p.join();
p=std::move(t.p);
return *this;
}
~unique_thread()
{
if(p.joinable())
p.join();
}
......//其他必要的成员函数
public:
unique_thread(const unique_thread&)=delete;
unique_thread& operator=(const unique_thread&)=delete;
};
int main()
{
unique_thread t1{std::thread(function_default)};
//unique_thread t1(std::thread(function_default)); 测试表明不能写成这种形式,应该是格式被编译器错误解析成了函数调用,改成{}形式的构造函数传参可以解决这个问题,也许养成使用{}进行对象构造的习惯是个不错的选择,但我目前还是习惯(), lol。
unique_thread t2(std::thread(function_para1,10));
return 0;
}
改天看看如何测试jthread类。
下一章来总结mutex