You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++20 std::jthread调用join失败报错,求正确停止线程的方法

如何正确停止std::jthread并避免join失败?

问题描述

使用C++20的std::jthread(apple-clang 14.0环境,依赖Nicolai Josuttis的实现),运行程序时在do_stuff()末尾调用thread.join()触发失败,程序输出错误:

Starting thread...
Max attempts exceeded.
libc++abi: terminating with uncaught exception of type std::__1::system_error: thread::join failed: Invalid argument

原代码如下:

#include <fmt/core.h>
#include <thread>

class ThreadedProcessor {

private:
    int attempt{0};
    const int max_attempts = 1;
    std::stop_source ssource;
    std::jthread thread;

    void do_stuff() {
        while (attempt < max_attempts) {
            ++attempt;
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
        fmt::print("Max attempts exceeded.\n");
        ssource.request_stop();
        thread.join();
    }

    void start() { // was previously called process()
        thread = std::jthread([&, stoken = ssource.get_token()]() {
            fmt::print("Starting thread...\n");
            while (!stoken.stop_requested()) {
                do_stuff();
            }
            if (stoken.stop_requested()) {
                fmt::print("Stop requested. Stopping thread.\n");
            }
        });
    }

public:

    ThreadedProcessor() {
        process();
    }
};

int main() {
    auto tp = ThreadedProcessor();
}

问题原因

  1. 非法的join调用:do_stuff()在子线程内部执行,此时thread对象关联的就是当前运行的子线程——线程自身调用join()属于非法操作,直接触发系统错误。
  2. 默认构造jthread的状态问题:默认构造的std::jthread处于非可结合状态(无关联执行线程),即便不在子线程内调用,直接对它执行join()也会报错。
  3. 线程启动笔误:构造函数里调用的process()是不存在的函数,实际应调用start(),这会导致线程根本没被正确启动。

解决方案

关键修正点

  • 移除子线程内的join调用:std::jthread核心特性就是自动管理线程生命周期,当jthread对象销毁时,会自动请求停止并等待线程结束(自动执行join()),完全不需要手动在子线程内调用join()。
  • 修正线程启动调用:把构造函数里的process()改为start(),确保线程被正确启动。
  • 利用jthread原生停止机制(可选优化):jthread会自动创建stop_source,并将对应的stop_token传递给线程函数,无需手动维护std::stop_source,简化代码逻辑。

修正后的完整代码

#include <fmt/core.h>
#include <thread>

class ThreadedProcessor {

private:
    int attempt{0};
    const int max_attempts = 1;
    std::jthread thread;

    void do_stuff() {
        while (attempt < max_attempts) {
            ++attempt;
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
        fmt::print("Max attempts exceeded.\n");
    }

    void start() {
        // 直接使用jthread自动传递的stop_token
        thread = std::jthread([this](std::stop_token stoken) {
            fmt::print("Starting thread...\n");
            while (!stoken.stop_requested()) {
                do_stuff();
                // 单次任务完成后主动检查停止请求,避免无限循环
                if (stoken.stop_requested()) {
                    break;
                }
            }
            fmt::print("Stop requested. Stopping thread.\n");
        });
    }

public:
    ThreadedProcessor() {
        start(); // 修正笔误,调用正确的启动函数
    }
};

int main() {
    auto tp = ThreadedProcessor();
    // 当tp销毁时,jthread会自动请求停止并join线程
}

额外说明

如果需要手动触发线程停止,可以给类添加一个公共方法:

void stop_processing() {
    if (thread.joinable()) {
        thread.request_stop();
    }
}

内容的提问来源于stack exchange,提问作者marital_weeping

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 07:50:30