1. 说明
使用Thread类创建线程对象的同时就会立刻启动线程,线程启动之后就要明确是等待线程结束(join)还是让其自主运行(detach),如果在线程销毁前还未明确上面的问题,程序就会报错。一般都会选择等待线程执行结束,如果不等待线程,即让其与主线程分离自主运行,那必须保证线程结束之前,可访问数据的有效性。
注意:当主线程碰到了子线程调用join()函数,程序会阻滞在当前行等待,直到当前子线程执行结束才会继续执行下面的代码。如果有多个线程需要同时执行,需要将每个线程的join()函数放到主线程的最后,才能避免阻滞现象。
2. 创建线程
使用thread类创建线程,主要有三种方式:①使用普通函数创建,②使用自定义类创建,③使用Lambda表达式创建
2.1 使用普通函数创建
此种方式,只是将普通函数的名字传输到thread构造函数中,注意不要再函数名字后面带()。
#include <iostream>
using namespace std;
#include <thread>
void myPrint()
{
cout << "我的线程开始执行了..." << endl;
cout << "我的线程执行完毕了..." << endl;
}
int main()
{
thread myThread(myPrint);//创建线程对象,并启动线程
myThread.join();//等待子线程执行结束后,再执行下面的代码
//myThread.detach(); //子线程与主线程分离,各自执行,互不影响(但子线程如果使用了主线程中的数据,当主线程结束后,子线程无法访问到数据时,会报错)
std::cout << "主线程收尾,最终主线程安全正常退出..."<<endl;
return 0;
}
2.2 使用自定义类创建
这种方法需要重载()运算符,把子线程需要执行的代码写到里面即可。而且此种方法将类对象名传输到thread类构造函数中后,实际上时调用了自定义类的拷贝构造函数复制了一份,线程执行结束后会调用自定义类的析构函数。
#include <iostream>
using namespace std;
#include <thread>
class background_task
{
public:
//构造函数
background_task()
{
cout << "这里时构造函数...." << endl;
}
//拷贝构造函数
background_task(const background_task& bg)
{
cout << "执行了拷贝构造函数...." << endl;
}
//析构函数(此案例中析构函数被调用两次,具体解释在下面)
~background_task()
{
cout << "执行了析构函数...." << endl;
}
//重载()运算符,将子线程需要执行的代码写入其中
void operator()() const
{
//在这里写子线程要执行的代码
cout << "我的线程开始执行...." << endl;
cout << "我的线程执行结束了...." << endl;
}
};
int main()
{
background_task f;//创建类对象(主线程结束后销毁此对象,会调用一次析构函数)
thread my_thread(f);//创建线程对象,并启动线程(线程结束后,在子线程空间内通过拷贝构造函数创建的对象也会被销毁,也会调用一次析构函数)
my_thread.join();
std::cout << "主线程收尾,最终主线程安全正常退出..."<<endl;
return 0;
}
程序输出结果:
2.3 使用Lambda表达式创建
这种方式创建比较简单,但是子线程中的代码不易重复使用
#include <iostream>
using namespace std;
#include <thread>
int main()
{
//使用lambda表达式创建线程
thread my_thread([] {
cout << "lambda表达式创建的线程开始执行....\n" << endl;
cout << "lambda表达式创建的线程执行结束....\n" << endl;
});
my_thread.join();
std::cout << "主线程收尾,最终主线程安全正常退出...\n"<<endl;
return 0;
}
3 扩展:
①:
子线程调用join()函数时,可以先使用joinable()函数判断是否能够加入,一个子线程只能加入一次,若能加入则返回true,否则返回false.
#include <iostream>
using namespace std;
#include <thread>
void myPrint()
{
cout << "我的线程开始执行了..." << endl;
cout << "我的线程执行完毕了..." << endl;
}
int main()
{
thread myThread(myPrint);//创建线程对象,并启动线程
if(myThread.joinable())
{
cout << "子线程能够使用join()或者detach()函数" << endl;
myThread.join();//等待子线程执行结束后,再执行下面的代码
}
else
{
cout << "子线程不能够使用join()或者detach()函数" << endl;
}
std::cout << "主线程收尾,最终主线程安全正常退出..."<<endl;
return 0;
}
②:
当有多个子线程需要同时进行时,最好将子线程的join()函数调用放到所有子线程的后面,这样能确保子线程之间不会等待
#include <iostream>
using namespace std;
#include <thread>
int main()
{
//使用lambda表达式创建线程
thread my_thread_1([] {
cout << "lambda表达式创建的线程 1 开始执行....\n" << endl;
cout << "lambda表达式创建的线程 1 执行结束....\n" << endl;
});
//my_thread_1.join();//如果在这里调用join,则子线程1执行结束后才能执行子线程2,因为join函数会阻塞后面的代码执行
thread my_thread_2([] {
cout << "lambda表达式创建的线程 2 开始执行....\n" << endl;
cout << "lambda表达式创建的线程 2 执行结束....\n" << endl;
});
my_thread_1.join();
my_thread_2.join();
std::cout << "主线程收尾,最终主线程安全正常退出...\n"<<endl;
return 0;
}