- 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()可使其在后台运行。