C++ 进程退出后,子线程还会存在吗?

本文通过四个实验详细探讨了C++中线程在不同情况下(局部变量和动态创建,detach与否)与进程退出的关系。实验表明,无论线程是否detach,当进程结束时,所有线程都会被强制终止,不会继续在后台运行。同时,局部变量线程在进程退出时可能会引发运行时异常。实验结果对于理解和正确使用C++线程至关重要。
摘要由CSDN通过智能技术生成

答案是:不会

那么我们接下来做做实验(实验内容已放到 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,也无论是否为局部变量(生命周期结束时被析构)。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值