如何在C++中创建和管理线程

C++11引入了<thread>头文件,提供了标准化的线程操作接口,使得多线程编程变得更加便捷和可移植

现代C++的线程管理以RAII 为核心原则,C++20引入的jthread进一步完善了自动管理机制


1. 创建线程(std::thread)

  • 线程对象:std::thread代表一个可执行的线程,可以传递函数指针、lambda表达式、仿函数等作为线程的执行内容
  • 核心原则:std::thread对象在销毁前必须调用join()/detach()函数,否则程序会直接终止(std::terminate)

2. 线程的生命周期管理

  • join():主线程调用join()来等待新线程的结束。join()确保主线程等待子线程完成,避免主线程提前结束,导致子线程被销毁。
cpp 复制代码
#include <iostream>
#include <thread>

static bool s_Finished = false;//所有线程共享的资源

void DoWork()
{
    using namespace std::literals::chrono_literals;

    std::cout << "Started thread id=" << std::this_thread::get_id() << std::endl;
    while (!s_Finished)//当其它线程将s_Finished设为true时,该线程结束
    {
        std::cout << "Working...\n";
        std::this_thread::sleep_for(1s);
    }
}

int main()
{
    std::thread worker(DoWork);//子线程开始执行

    std::cin.get();//主线程等待用户按下回车(主线程停滞)
    s_Finished = true;//用户按下回车后,主线程将s_Finished设为true

    worker.join();//主线程等待子线程worker结束
    std::cout << "Finished" << std::endl;

    std::cin.get();
}
  • detach():将线程与线程对象完全分离,不再受主线程或原线程对象的控制,线程在后台独立运行,直至线程结束。执行完成后,自动释放所有资源。
cpp 复制代码
#include <iostream>
#include <string>
#include <thread>

void bgTask()
{
    for (int i = 0; i < 5; ++i)
    {
        std::cout << "background running..." << i << std::endl;
    }
    std::cout << "Finished" << std::endl;
}

int main()
{
    //将该线程与线程对象完全分离,不在首主线程或原线程对象的控制
    //该线程在后台独立运行
    std::thread(bgTask).detach();

    //主线程退出会杀死所有分离线程,必须给足够的运行时间
    std::cin.get();//主线程停滞
}

3. 线程的返回值

std::thread本身不支持返回值。

C++标准库提供了获取线程返回值的多种方式:

  • std::async会自动创建一个线程并返回一个future对象,对future对象调用get()函数可以阻塞等待并获取返回值
cpp 复制代码
#include <iostream>
#include <thread>
#include <chrono>
#include <future>

int add(int a, int b)
{
    std::cout << "Started thread id=" << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    return a + b;
}

int main()
{
    //异步执行,返回future
    std::future<int> result = std::async(add, 10, 20);

    //主线程停滞,等待获取线程的返回结果
    std::cout << "Result: " << result.get() << std::endl;
    
    std::cin.get();
    std::cout << "main thread Finished" << std::endl;
}

在C++中,我们通过std::thread创建线程,通过传入函数指针,Lambda表达式,类成员函数等 来指定线程的执行内容。

通过join()/detach()来管理类的生命周期,join()确保主线程等待子线程的结束,避免主线程提前结束,导致子线程被销毁;detach()将线程与线程对象完全分离,线程独立运行在后台,线程结束后自动释放所有资源,分离的线程由C++运行时托管,无法获取到其状态或结果,也无法再管理其生命周期(确保给足够的运行时间,主线程结束会杀死所有分离线程)。

如果不对一个线程对象调用join()/detach(),C++会直接终止程序,这也是C++防止线程泄漏的手段。

在C++20中,更推荐使用jthread,它在线程对象析构时,自动调用join(),避免了手动调用join()的潜在风险。

多线程环境下,共享数据必须通过同步机制保护------最常见的是std::mutex配合std::lock_guard实现RAII 式加锁保护,或者使用std::atomic实现无锁并发编程。

对于简单异步任务,使用std::async封装比手动管理线程更加高效,它能自动处理结果返回和异常传递。

总的来说,C++线程管理的核心在于严格遵守"创建-同步-回收"的生命周期,优先使用现代工具,如jthreadstd::async,并始终要确保共享数据的线程安全

面试官可能追问

  • 为什么detach()后无法管理线程的生命周期?

答:detach()后,线程与线程对象完全分离,该线程由C++运行时托管,无法再获取其状态和结果,也无法管理其生命周期。

  • 何时用join(),何时用detach() ?

答:join()用在需要等待的场景;detach()用在后台监控、日志写入等无需交互的任务。

相关推荐
小小龙学IT43 分钟前
ZeroMQ(libzmq)开源消息库深度解析:brokerless 时代的轻量消息内核
c++·开源
Benny_Tang1 小时前
题解:P10230 [COCI 2023/2024 #4] Lepeze
c++·算法
我变成萤火虫2 小时前
反悔贪心(经典题目讲解)
c++·算法·贪心算法·stl·排序算法·反悔贪心
_Narcissus_2 小时前
排序算法总结表格
c语言·数据结构·c++·笔记·算法·排序算法·总结
兔兔兔兔14 小时前
记录C++ 8
开发语言·c++
脑子不好的小菜鸟5 小时前
秋招、实习 小知识点复习 (C/C++/Linux)—— 碎片时间可看
c++·求职招聘
charlie1145141916 小时前
深探std::vector:三指针、扩容与迭代器失效
开发语言·c++·开源项目
laplaya6 小时前
ROS常用消息之PointCloud2
c++
沙盘客7 小时前
典型应用与趋势:作战实验、AI 决策与数字孪生
c++·人工智能·经验分享
ShineWinsu7 小时前
对于 C++ :从 const、constexpr、auto、decltype 到 type_traits、SFINAE 与 Concepts的解析
c++