C++20标准新增的jthread类是对传统thread的重要升级,它内置了停止令牌机制和自动join特性,不需要开发者手动调用join方法就能保证线程资源被正确回收,同时支持更优雅的线程停止逻辑,非常适合需要长期运行或需要可控停止的线程场景。

jthread与传统thread的核心区别
传统thread在使用时需要开发者手动处理线程的回收逻辑,如果忘记调用join或者detach,程序结束时可能会抛出std::system_error异常。而jthread在析构时会自动调用join,同时支持通过停止令牌向线程发送停止请求,两者的核心差异如下:
| 特性 | thread | jthread |
|---|---|---|
| 析构行为 | 若未join或detach,析构时抛异常 | 析构时自动调用join,无异常 |
| 停止机制 | 无内置停止机制,需自行实现 | 内置停止令牌,支持停止请求 |
| 停止回调 | 不支持 | 支持注册停止时的回调函数 |
基础jthread使用示例
最简单的jthread使用方式和传统thread类似,直接传入可调用对象即可,不需要手动管理生命周期:
#include <iostream>
#include <thread>
#include <chrono>
// 线程执行函数
void worker_task() {
for (int i = 0; i < 5; ++i) {
std::cout << "线程执行第" << i << "次任务" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
int main() {
// 创建jthread,自动管理生命周期
std::jthread t(worker_task);
// 不需要手动调用t.join(),jthread析构时会自动处理
// 主线程等待3秒后,jthread会随着main函数结束自动析构并join
std::this_thread::sleep_for(std::chrono::seconds(3));
return 0;
}
上述代码中,jthread对象t在main函数结束时析构,会自动等待worker_task执行完成,不需要开发者手动调用join方法,避免了遗漏join导致的异常问题。
使用停止令牌控制线程停止
jthread的核心优势之一是内置了std::stop_token,可以向线程发送停止请求,线程可以主动检查停止状态并退出执行。创建jthread时,如果可调用对象的第一个参数是std::stop_token,jthread会自动把停止令牌传递给线程函数:
#include <iostream>
#include <thread>
#include <chrono>
// 带停止令牌的线程函数,第一个参数为std::stop_token
void stoppable_task(std::stop_token st) {
int count = 0;
// 循环检查停止令牌的状态
while (!st.stop_requested()) {
std::cout << "可停止线程执行第" << count << "次任务" << std::endl;
++count;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
std::cout << "收到停止请求,线程退出" << std::endl;
}
int main() {
// 创建jthread,自动传递停止令牌给stoppable_task
std::jthread t(stoppable_task);
// 主线程等待3秒后,调用request_stop发送停止请求
std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout << "主线程发送停止请求" << std::endl;
t.request_stop();
// 这里不需要手动join,jthread析构时会自动等待线程退出
return 0;
}
运行上述代码,线程会执行3次任务后,收到主线程的停止请求,然后主动退出循环,最终jthread析构时自动完成join操作。
注册停止回调
除了在线程函数中主动检查停止令牌的状态,jthread还支持通过std::stop_callback注册停止时的回调函数,当停止请求被发送时,回调函数会自动执行,适合需要在线程外处理停止逻辑的场景:
#include <iostream>
#include <thread>
#include <chrono>
void task_with_callback(std::stop_token st) {
// 注册停止回调,当停止请求到来时执行
std::stop_callback cb(st, [](){
std::cout << "停止回调执行:清理线程相关资源" << std::endl;
});
int count = 0;
while (!st.stop_requested()) {
std::cout << "带回调的线程执行第" << count << "次任务" << std::endl;
++count;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
int main() {
std::jthread t(task_with_callback);
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "主线程发送停止请求" << std::endl;
t.request_stop();
return 0;
}
当主线程调用request_stop后,注册的停止回调会首先执行,完成资源清理工作,之后线程函数再检查到停止请求退出循环,整个停止流程更加可控。
使用注意事项
- jthread是C++20新增特性,需要编译器支持C++20标准,编译时需要添加对应的编译选项,比如GCC需要添加-std=c++20参数。
- 停止令牌的停止请求是一次性的,一旦发送后状态就会变为已请求,无法重置。
- 如果线程函数没有接收
std::stop_token参数,jthread的停止机制不会生效,此时jthread仅具备自动join的特性。 - 不要在jthread对象上手动调用join或者detach,否则会触发未定义行为,jthread的设计目标就是自动管理这些操作。