C++学习 初识多线程 <thread>标准库的join/detach函数
- join()函数和detach()函数有什么作用?
请看下面的例子,我们首先创建两个线程并让其自行执行;
#include<thread> #include<iostream> using namespace std; void func1(){ for(int i = 0; i < 10; i++) cout << i; } void func2(){ for(int i = 0; i < 10; i++) cout << char('a'+i); } int main(){ thread t1(func1); thread t2(func2);return 0; }
// output is empty
如果直接在主线程中创建子线程并执行,则主线程往往先于子线程执行完毕(先获得CPU的控制权),导致整个进程的异常。因此,我们需要使用join()函数将子线程阻塞。
在哪个线程函数内创建线程,则两个线程就为父子关系;
在父线程函数内使用子线程的join函数,则将父线程阻塞,等待被join的子线程执行完毕才能继续执行完父线程。
void func2(){ for(int i = 0; i < 10; i++) cout << char('a'+i); } void func1(){ thread t2(func2); t2.join(); for(int i = 0; i < 10; i++) cout << i; } int main(){ thread t1(func1); t1.join(); return 0; }
总之,join用于阻塞当前线程等待thread执行完执行体。一般用于多线程之间进行同步。对于不具备分离属性的线程必须要join,否则会导致terminal。
上面我们了解到,线程间是并行运行的,但是如果主线程先结束会导致子线程也结束,导致进程异常;利用join()函数我们可以使线程间串行运行。
如果需要线程间并行运行,且子线程与父线程分离,当父线程执行结束后子线程不会随之一起结束,而是自行在后台运行,这是detach()函数的作用。
#include <iostream> // std::cout #include <thread> // std::thread, std::this_thread::sleep_for #include <chrono> // std::chrono::seconds void pause_thread(int n) { std::this_thread::sleep_for (std::chrono::seconds(n)); std::cout << "pause of " << n << " seconds ended\n"; } int main() { std::cout << "Spawning and detaching 3 threads...\n"; std::thread (pause_thread,3).detach(); std::thread (pause_thread,1).detach(); std::thread (pause_thread,2).detach(); std::cout << "Done spawning threads.\n"; std::cout << "(the main thread will now pause for 5 seconds)\n"; // give the detached threads time to finish (but not guaranteed!): pause_thread(3); return 0; }
上面的代码中,3个子线程将会脱离主线程自行运行。但是!所谓的后台运行显然让控制台中的输出结果无法被观测,因此我们利用下面的代码证明detach的线程仍在后台运行。
#include<iostream> #include<thread> #include<fstream> #define pi 3.1415926 using namespace std; double compute(int i){ double temp = 1; for(int j = 0; j < 100000000; j++){ temp *= pi; temp /= i; } return temp; } void write_file(){ fstream file("./log.txt"); for(int i = 1; i < 100; i++){ file << i << ' ' << compute(i) << endl; } return ; } int main(){ // write_file(file); thread (write_file).detach(); for(int i = 1; i < 20; i++){ // 作耗时的浮点数运算 cout << i << ' ' << compute(i) << endl; } return 0; }
结果被打脸了,主线程结束后子线程也结束了,说好了在后台运行呢?
上面的代码在主线程结束后,子线程也随之结束。因此这里的“后台运行”还需要进一步理解。
请看下面的代码:
#include<iostream> #include<thread> #include<fstream> #define pi 3.1415926 using namespace std; double compute(int i){ double temp = 1; for(int j = 0; j < 100000000; j++){ temp *= pi; temp /= i; } return temp; } void print(){ for(int i = 1; i < 100; i++){ cout << i << ' ' << compute(i) << endl; } return ; } void write_file(){ fstream file("./log.txt"); thread t(print); // 注意这里没加detach,加了detach()之后子线程不会随父线程关闭 for(int i = 1; i < 20; i++){ file << i << ' ' << compute(i) << endl; } return ; } int main(){ thread (write_file).detach(); system("pause"); return 0; }
直接创建线程并运行,结果在父线程write_file结束后,print子线程也随之结束,报错
“terminate called without an active exception”
detach()函数可以使一个线程变为non-joinable状态,从而无法对父线程进行阻塞。
当父线程不是主线程时,对子线程加detach()可使其在后台运行。