答案是:不会
那么我们接下来做做实验(实验内容已放到 github 上,详见此处):
实验1:局部变量线程,detach
#include <iostream>
#include <memory>
#include <thread>
#include "GetTimeStamp.h"
void LoopForever() {
while(true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << GetTimeStamp() << std::endl;
};
}
int main(int argc, char** argv)
{
std::thread a(LoopForever); // 首先,我们以局部变量的形式创建一个子线程
a.detach(); // 然后 detach 子线程
std::this_thread::sleep_for(std::chrono::seconds(5)); // 等待5秒后,退出进程
return 0;
}
实验结果如下图所示,5秒后子线程终止。
当进程结束时,所有线程将被中止,不会继续在后台进行。详细可以在《简单了解C语言中主线程退出对子线程的影响》一文中了解。
实验2:动态创建线程,detach
#include <iostream>
#include <memory>
#include <thread>
#include "GetTimeStamp.h"
void LoopForever() {
while(true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
auto stamp = GetTimeStamp();
std::cout << stamp << std::endl;
};
}
int main(int argc, char** argv)
{
auto a = new std::thread(LoopForever); // 首先,我们动态创建一个子线程
a->detach(); // 然后 detach 子线程
std::this_thread::sleep_for(std::chrono::seconds(5)); // 等待5秒后,退出进程
return 0;
}
那么使用 new 动态创建线程,是否和局部变量一致呢?答案是肯定的
实验3:动态创建线程,直接退出进程
#include <iostream>
#include <fstream>
#include <memory>
#include <thread>
#include "GetTimeStamp.h"
#define DO_NOTHING 1
#define DETACH 1
void LoopForever() {
std::ofstream of("interview_demo.log", std::ios::trunc);
while(true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
auto stamp = GetTimeStamp();
std::cout << stamp << std::endl;
of << stamp << std::endl;
};
}
int main(int argc, char** argv)
{
auto a = new std::thread(LoopForever); // 首先,我们动态创建一个子线程
std::this_thread::sleep_for(std::chrono::seconds(5)); // 等待5秒后,退出进程
return 0;
}
使用 new 动态创建线程,直接退出进程的话,与之前的实验结果一致,子线程退出。
实验4:局部变量线程,直接退出进程
#include <iostream>
#include <memory>
#include <thread>
#include "GetTimeStamp.h"
void LoopForever() {
while(true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << GetTimeStamp() << std::endl;
};
}
int main(int argc, char** argv)
{
std::thread a(LoopForever); // 首先,我们以局部变量的形式创建一个子线程
std::this_thread::sleep_for(std::chrono::seconds(5)); // 等待5秒后,退出进程
return 0;
}
上述代码其实可以编译通过,只是会抛出运行时的异常,这个异常只会在Debug版本被抛出,应该是在局部变量析构时检测到了异常。
而且,线程其实不会立刻终止,而是会在点击对话框中的“中止”按钮前,继续运行。
附 GetTimeStamp.h 代码,用于生成时间戳
#pragma once
#include <cstdint>
#include <thread>
#include <sstream>
#include <string>
#include <iostream>
#include <iomanip>
static std::string GetTimeStamp()
{
std::stringstream ss;
auto now = std::chrono::system_clock::now();
auto now_t = std::chrono::system_clock::to_time_t(now);
tm now_tm;
#if defined(_WIN32)
localtime_s(&now_tm, &now_t);
#elif defined(MS_LINUX)
localtime_r(&now_t, &now_tm);
#endif
ss << std::setfill('0') << std::setw(2) << now_tm.tm_hour
<< ":" << std::setfill('0') << std::setw(2) << now_tm.tm_min
<< ":" << std::setfill('0') << std::setw(2) << now_tm.tm_sec;
auto tp = now.time_since_epoch();
auto ms =
std::chrono::duration_cast<std::chrono::milliseconds>(tp)
- std::chrono::duration_cast<std::chrono::seconds>(tp);
ss << "." << std::setfill('0') << std::setw(3) << ms.count();
return ss.str();
}
小结
子线程在进程退出时会“被退出”,无论是否detach,也无论是否为局部变量(生命周期结束时被析构)。