线程的创建有3种方式:默认构造函数、初始化构造函数 和 移动构造函数
默认构造函数方式和初始化构造函数方式类似,在这里不过多介绍
初始化构造函数其实就是把 线程函数的指针 和 线程函数的参数 一同传入线程类的构造函数中。
#include <iostream> #include <thread> using namespace std; void thread_func_with_arg(); void thread_func_with_one_arg(int arg_1); void thread_func_with_two_arg(int arg_1, int arg_2); int main(int argc, char* argv) { cout << "//---------------------- program start -----------------------//" << endl; cout << "----> This is the main thread." << endl; // 创建线程 thread thread_0(thread_func_with_arg); // 无参数线程 thread thread_1(thread_func_with_one_arg, 1); // 带一个参数线程 thread thread_2(thread_func_with_two_arg, 2, 3); // 带两个参数线程 // 等待线程结束 thread_0.join(); thread_1.join(); thread_2.join(); cout << "//---------------------- program end -----------------------//" << endl; return EXIT_SUCCESS; } void thread_func_with_arg() { cout << "--------> This is a thread without id" << endl; } void thread_func_with_one_arg(int arg) { cout << "--------> This is thread with one arg: " << arg << endl; } void thread_func_with_two_arg(int arg_1, int arg_2) { cout << "--------> This is thread with two args" << endl << " * arg_1: " << arg_1 << endl << " * arg_2: " << arg_2 << endl; }注意g++编译时,需要加上链接参数 -lpthread.
输出结果为:
//---------------------- program start -----------------------// ----> This is the main thread. --------> This is a thread without id --------> This is thread with two args * arg_1: 2 * arg_2: 3 --------> This is thread with one arg: 1 //---------------------- program end -----------------------//在这个例子中,分别创建了3个线程,其中一个线程没有输入参数,一个带有一个输入参数,一个带有两个输入参数。
现在不太理解这个移动构造函数,也没看出来这个操作具体有什么优势,这里就不写了以免误导大家,想要深入的话可以参考这个:https://blog.csdn.net/chengqiuming/article/details/89276875
首先我们需要理解:当主线程创建新的子线程后,如果子线程没有被分离(detach),则 当主线程结束的时候,如果子线程还没有结束,则会强制结束子线程。
而join() 函数的功能是 阻塞 调用对象线程(主线程),并 等待子线程结束 ,子线程结束后,再继续执行主线程剩下的任务。
尝试运行下面的程序:
#include <iostream> #include <thread> #include <unistd.h> using namespace std; void thread_func(); int main(int argc, char* argv[]) { cout << "//---------------------- program start -----------------------//" << endl; thread sub_thread(thread_func); // sub_thread.join(); // 1. 有调用 join() 的时候,程序能没有错误地结束 // 2. 如果不调用 join(), 则在程序结束时,会提示: // “terminate called without an active exception” for(int i=0; i<5; i++) { cout << "主线程计数: " << i << endl; usleep(500000); } cout << "//---------------------- program end -----------------------//" << endl; return EXIT_SUCCESS; } void thread_func() { cout << "--> 子线程开始" << endl; for(int i=0; i<10; i++) { cout << "子线程计数: " << i << endl; usleep(500000); } cout << "--> 子线程结束" << endl; return; }如果注释掉 join() 函数,你会得到类似下面的结果:
//---------------------- program start -----------------------// 主线程计数: 0 --> 子线程开始 子线程计数: 0 主线程计数: 1 子线程计数: 1 主线程计数: 2 子线程计数: 2 主线程计数: 3 子线程计数: 3 主线程计数: 4 子线程计数: 4 //---------------------- program end -----------------------// 子线程计数: 5 terminate called without an active exception如果你的结果出现如“主线程计数: 主线程计数: 33”这样的情况,这是因为在打印的时候没有加 锁 ,关于线程的锁会在后面再提及。
这里可以看到,子线程并没有完全执行(计数到9),而是当主线程结束的时候,就被强制结束了。
而如果调用 join() 的话,结果会是:
//---------------------- program start -----------------------// --> 子线程开始 子线程计数: 0 子线程计数: 1 子线程计数: 2 子线程计数: 3 子线程计数: 4 子线程计数: 5 子线程计数: 6 子线程计数: 7 子线程计数: 8 子线程计数: 9 --> 子线程结束 主线程计数: 0 主线程计数: 1 主线程计数: 2 主线程计数: 3 主线程计数: 4 //---------------------- program end -----------------------//这是因为当调用了 join() 之后,主线程会被阻塞,等待子线程完成,然后 join() 函数才会有返回,join() 函数返回后,主线程方可继续执行它自己的任务。
上面说到利用 join() 函数,可以阻塞主线程,等待子线程完成以后在继续主线程,从而避免当主线程结束的时候强制结束子线程的问题。
那有没有办法可以既不阻塞主线程,又能保证子线程能够在完成后再结束呢?这时就需要使用 detach() 函数。
detach() 函数可以使子线程从主线程中 分离 出来,当主线程结束的时候,不会再强制结束子线程。
将上面程序的 join() 函数换成 detach()
int main(int argc, char* argv[]) { ~~~ thread subThread(thread_func); subThread.detach(); ~~~ } //---------------------- program start -----------------------// 主线程计数: 0 子线程计数: 0 主线程计数: 1 子线程计数: 1 子线程计数: 2 主线程计数: 2 子线程计数: 3 主线程计数: 3 子线程计数: 4 主线程计数: 4 子线程计数: 5 //---------------------- program end -----------------------//使用了detach() 函数,当主线程结束后,并没有强制结束子线程(没有报“terminate called without an active exception”),这时其实子线程是在后台继续运行的。
哈,暂时没想到有什么简单的方法证明子线程还在运行,先这样吧。