Wiki
jthread and stop_token
Existing English translations were reused. 2 current source blocks remain in Simplified Chinese, without triggering paid translation.
C++20 provides:
std::jthread
It can be understood as athread class more suitable for modern C++.
Compared with std::thread, it has two most important improvements:
1. 生命周期更安全
→ 析构时自动处理线程,不容易因为漏写 join() 而出问题
2. 自带协作式停止机制
→ 可以通过 stop_token / request_stop() 请求线程安全退出
So the most important thing in this section is to separate the two concepts:
线程生命周期管理
→ 谁负责等待线程结束
线程停止协议
→ 谁发出停止请求,工作线程怎么响应
std::jthread It solves both problems at the same time, but it is not a tool for “automatically force-killing threads.”
1.Why is it necessary to std::jthread
1.1.std::thread issue
Use the standard std::thread:
std::thread thread(work);
Before a thread object is destroyed, it must be ensured that it has already:
thread.join();
Or:
thread.detach();
Otherwise, if a still joinable() of the std::thread is destructed, the program calls:
std::terminate();
For example:
#include <print>
#include <thread>
void work()
{
std::println("working");
}
int main()
{
std::thread thread(work);
// 如果这里忘记 join() / detach()
}
When the program exits main(), thread is still joinable, so std::terminate() is triggered.

The real trouble is when the following appears in the program:
异常
提前 return
多个 if / else 分支
复杂资源管理
it is easier to miss join().
This is somewhat similar to manually managing new/delete:
代码简单时看起来没问题
控制路径一复杂
→ 很容易忘记收尾
Modern C++, however, tends to manage resources automatically through RAII.
Threads are the same.
1.2.std::jthread will automatically handle thread termination
The simplest example:
#include <print>
#include <thread>
void work()
{
std::println("working");
}
int main()
{
std::jthread thread(work);
}
Output result:
working

It is not written here:
thread.join();
However, the program can still terminate normally.
Because when:
std::jthread thread;
When leaving scope, if it is still joinable, the destructor is responsible for cleanup.
It can first be roughly understood as:
std::thread
→ 需要自己保证 join() / detach()
std::jthread
→ 析构时自动处理
However, jthread the destructor is not simply join().
More precisely, if it is still joinable, the destruction process conceptually does the following:
request_stop()
↓
join()
That is:
First request the thread to stop, then wait for the thread to actually terminate.
This is also jthread and the regular thread an important difference.
1.3.jthread Will not forcibly kill the thread
std::jthread Uses:
cooperative cancellation
The so-called “collaborative” means:
某个线程:
发出停止请求
↓
工作线程:
看到停止请求
↓
工作线程:
自己选择一个安全的位置退出
rather than:
request_stop()
↓
操作系统立刻把工作线程强行杀掉
The standard library will not arbitrarily kill a thread directly in the middle of a machine instruction.
The reason is simple.
Thread may be:
持有 mutex
修改共享数据
写文件
操作硬件
分配 / 释放资源
修改对象内部状态
If a thread is forcibly terminated at an arbitrary point, it is very easy to corrupt the program state.
Therefore:
thread.request_stop();
It is more like telling the worker thread:
“You should stop now; please exit on your own at an appropriate point.”
rather than:
"Kill you right now this instant."
2.stop_token Stop Protocol
2.1.std::stop_token
2.1.1.stop_token What is it
std::stop_token It can be understood as:
Observation side that stops the request.
It itself cannot issue a stop request; it can only view:
有没有人要求我停止?
For example:
stop_token.stop_requested();
Return:
true → 已经有人请求停止
false → 目前还没有停止请求
jthread Internally, there is a stop state, which can be roughly understood as:
jthread / stop_source
↓
发出停止请求
共享停止状态
↑
查看停止请求
↑
stop_token
In other words:
request_stop()
→ 写入“停止请求”
stop_requested()
→ 查看“停止请求”
2.2.jthread can be automatically passed in stop_token
Let's look at a most typical example:
#include <chrono>
#include <print>
#include <stop_token>
#include <thread>
using namespace std::chrono_literals;
void worker(std::stop_token token)
{
while (!token.stop_requested())
{
std::println("working");
std::this_thread::sleep_for(100ms);
}
std::println("stopping");
}
int main()
{
std::jthread thread(worker);
std::this_thread::sleep_for(350ms);
thread.request_stop();
}
Possible output:
working
working
working
working
stopping
What is most special here is:
void worker(std::stop_token token)
However, when creating the thread, it was only written as:
std::jthread thread(worker);
We did not pass it manually:
worker(token);
Because std::jthread discovers that this function can accept std::stop_token,so it automatically passes its own stop token in.
It can be approximately understood as:
std::jthread thread(worker);
内部效果类似:
worker(jthread 自动提供的 stop_token);
Explicit arguments cannot be provided here, for examplestd::jthread thread(worker, thread.get_stop_token()); This is illegal, and the reason is straightforward: when the constructor arguments are being executed, the thread object has not yet been fully constructed, so you cannot callthread.get_stop_token().
So just remember here that it will automatically pass its ownstop tokenargument in, and we do not need to pass it manually.
2.3.request_stop()
Call:
thread.request_stop();
Indicates:
Send a stop request to the stop state associated with this
jthread.
It is only responsible for "sending requests".
It will not:
强制终止线程
自动跳出 while
直接让 worker return
等待线程结束
It is actually the worker thread that decides when to exit.
For example:
while (!token.stop_requested())
{
do_work();
}
Check each cycle:
token.stop_requested()
Exit the loop as soon as a stop request is detected.
The entire process is:
main
│
│ 创建 jthread
↓
worker 开始执行
│
│ while (!token.stop_requested())
│
│ working...
│
│ working...
│
↑
main 调用 request_stop()
│
↓
停止状态变成“已请求停止”
│
↓
worker 下一次检查 stop_requested()
│
↓
发现为 true
│
↓
退出循环
So the most important sentence is:
request_stop()It is only a request to stop; actual termination must be cooperatively handled by the worker thread itself.
2.4.request_stop() return value of
request_stop() returns a bool:
bool result = thread.request_stop();
It can be roughly understood as:
true
→ 这次调用真的把状态从
“还没请求停止”
改成了
“已经请求停止”
false
→ 之前已经请求过停止
或者当前停止状态无法产生停止请求
Ordinary business code often does not need to care about this return value.
Write directly:
thread.request_stop();
That will do.
2.5.stop_possible()
stop_token can also be called:
token.stop_possible();
It means:
Whether this token is associated with a stopped state that "may receive a stop request."
For example:
std::stop_token token;
This is a default-constructed token, which does not have an associated normal stopped state.
At this point, typically:
token.stop_possible() == false
token.stop_requested() == false
and std::jthreadThe automatically provided token is usually:
stop_possible() == true
For ordinary use, the most commonly used ones are still:
stop_requested()
stop_possible()It is more often used when it is necessary to determine whether "this token actually supports the stop protocol".
2.6.jthread What exactly happens during destruction
Assumption:
{
std::jthread thread(worker);
}
Execute to the closing curly brace:
}
thread Begin destruction.
If it is still joinable, then conceptually it would:
thread.request_stop();
↓
thread.join();
Therefore:
{
std::jthread thread(worker);
}
It can be understood as automatically performing the following when exiting the scope:
thread.request_stop();
thread.join();
This is also why this kind of code can work properly:
#include <print>
#include <stop_token>
#include <thread>
void worker(std::stop_token token)
{
while (!token.stop_requested())
{
// work
}
std::println("stopped");
}
int main()
{
std::jthread thread(worker);
}
main() At the end:
jthread 析构
↓
request_stop()
↓
worker 看到停止请求
↓
worker 退出
↓
join() 等待结束
↓
析构完成
2.7.However, destruction cannot "make a thread exit out of thin air."
The following thread does not check at all stop_token:
void worker(std::stop_token)
{
for (;;) //死循环,效率比while(true)高
{
}
}
Then:
int main()
{
std::jthread thread(worker);
}
Leavemain() when:
jthread 析构
↓
request_stop()
↓
停止请求确实发出了
↓
但是 worker 根本不检查
↓
for(;;) 继续运行
↓
析构函数接着 join()
↓
join() 一直等
the program will just keep getting stuck there.
Therefore:
jthreadWhat is provided is a stop protocol, not a forced termination capability.
Therefore, for long-running workers, one should generally check at an appropriate location:
token.stop_requested()
For example:
while (!token.stop_requested())
{
do_some_work();
}
Rather than checking only once at the beginning of the thread:
if (token.stop_requested())
{
return;
}
// 后面运行几个小时都不再检查
2.8.Blocking operations also affect the stop speed.
Even if the code is written as:
while (!token.stop_requested())
{
blocking_operation();
}
It also does not mean that the thread will necessarily stop immediately.
Assumption:
blocking_operation();
It will block for 30 seconds at a time.
Then even if it has already been executed externally:
thread.request_stop();
The worker thread must also first start from:
blocking_operation();
Only after returning can the next round proceed:
token.stop_requested()
Therefore, the stop response speed also depends on what the worker thread is doing internally.
For threads that need to stop quickly, consider:
阻塞函数有没有超时
阻塞操作能不能被唤醒
能不能把长任务拆成多个小步骤
能不能在多个安全点检查 stop_requested()
For example:
while (!token.stop_requested())
{
do_small_step();
}
Usually compared to:
while (!token.stop_requested())
{
do_one_huge_blocking_job();
}
It is easier to respond quickly to a stop request.
2.9.std::stop_source
As mentioned earlier:
stop_token
→ 观察停止请求
So who is responsible for issuing the stop request?
Besides jthread.request_stop(), the standard library also provides:
std::stop_source
It can be understood as:
The control end that stops the request.
For example:
#include <print>
#include <stop_token>
int main()
{
std::stop_source source;
std::stop_token token = source.get_token();
std::println("{}", token.stop_requested());
source.request_stop();
std::println("{}", token.stop_requested());
}
Output result:
false
true
The entire relationship can be understood as:
stop_source
│
│ request_stop()
↓
共享停止状态
↑
│ stop_requested()
stop_token
Therefore:
std::stop_source source;
Responsible for:
发请求
And:
std::stop_token token = source.get_token();
Responsible for:
看请求
2.10.Multiple stop_token can observe the same stop state
For example:
std::stop_source source;
std::stop_token token1 = source.get_token();
std::stop_token token2 = source.get_token();
std::stop_token token3 = source.get_token();
These three tokens are all associated with the same stop state.
When:
source.request_stop();
Afterwards:
token1.stop_requested()
token2.stop_requested()
token3.stop_requested()
will all become:
true
So stop_source + stop_token is very suitable for expressing:
一个管理者
↓
统一发出停止请求
↓
多个任务 / 对象
↓
一起观察同一个停止状态
2.11.std::stop_callback
Sometimes we don't want to keep checking manually:
token.stop_requested()
Instead, the hope is:
Automatically perform an operation once a stop request occurs.
Can be used:
std::stop_callback
For example:
#include <print>
#include <stop_token>
int main()
{
std::stop_source source;
std::stop_token token = source.get_token();
std::stop_callback callback(token, [] {
std::println("stop requested");
});
source.request_stop();
}
Output result:
stop requested
In other words:
request_stop()
↓
停止状态改变
↓
已经注册的 stop_callback 被调用
If he isjthreadcalling it, then the order is:
request_stop()
↓
同步执行 stop_callback
↓
request_stop() 返回
↓
join()
In other words, the callback completes before join(). The destruction of std::jthread itself first calls request_stop() and then calls join().
It is well suited for doing some very lightweight things, for example:
设置状态
唤醒某个等待对象
通知某个组件开始收尾
However, it is not recommended to do the following inside the callback:
复杂计算
长时间 IO
长时间阻塞
大量锁操作
Because the stop path itself should be as simple and controllable as possible.
One more detail:
If the stop request has already occurred when the callback is registered, the callback may execute directly during the registration process.
So do not assume:
callback 一定会在未来某个时间
由另一个线程执行
3.Thread functions and lifecycle operations of jthread
3.1.jthread It is not necessary to use stop_token
std::jthread It can also run normal functions like a normal std::thread.
For example:
#include <print>
#include <thread>
void work(int value)
{
std::println("{}", value);
}
int main()
{
std::jthread thread(work, 42);
}
Output result:
42
Here:
void work(int value)
Simply no stop_token.
It doesn't matter.
jthreadIt will determine whether this function can receive an automatically provided stop token.
It can be simply understood as:
如果函数可以这样调用:
worker(stop_token, args...)
→ 自动传入 stop_token
否则如果函数只能这样调用:
worker(args...)
→ 就像普通 thread 一样调用
So both notations are acceptable:
void worker(std::stop_token token);
And:
void worker();
3.2.带额外参数的 stop_token 线程函数
For example:
#include <print>
#include <stop_token>
#include <thread>
void worker(std::stop_token token, int id)
{
std::println("worker {}", id);
while (!token.stop_requested())
{
// work
}
}
int main()
{
std::jthread thread(worker, 7);
thread.request_stop();
}
Here:
std::jthread thread(worker, 7);
It can be understood as the final call:
worker(自动提供的 stop_token, 7);
So if the function requires a stop token, the parameter order is usually:
void worker(std::stop_token token, 参数1, 参数2, ...)
For example:
void worker(
std::stop_token token,
int id,
std::string name);
Create:
std::jthread thread(worker, 7, "camera");
Equivalent to:
worker(
自动提供的 stop_token,
7,
"camera"
)
3.3.jthread Still can manually join()
Although jthread joins automatically, you can still write it yourself:
std::jthread thread(work);
thread.join();
Execution completed:
thread.join();
Later:
thread.joinable()
It becomes:
false
Because this jthread is no longer associated with a joinable execution thread.
Therefore:
自动 join
does not mean:
不能手动 join
It simply means:
If you didn't handle it manually, the destructor will safely wrap things up for you.
3.4.jthread can also detach() , but it is usually not recommended
jthread Still provides:
thread.detach();
But after doing this:
jthread 不再拥有这个线程
析构时也没办法再 join 它
Thus, jthread the most important RAII lifetime advantage is essentially lost.
So if you find yourself about to write:
thread.detach();
It is best to ask a few questions first:
这个线程以后由谁负责?
程序退出时它怎么结束?
它访问的对象会不会已经析构?
它访问的资源能活多久?
Unless you are very clear about how to manage the thread lifecycle, it is generally not recommended to detach casually.
3.5.condition_variable_any and stop_token
A question was mentioned earlier:
If the thread is:
condition_variable.wait(...)
If sleeping inside, then only check:
token.stop_requested()
is not enough.
Because the thread may never get a chance to execute up to the next check.
C++ 20:
std::condition_variable_any
Provides a waiting method that can be used directly with stop_token.
For example:
#include <condition_variable>
#include <mutex>
#include <stop_token>
#include <thread>
std::mutex mutex;
std::condition_variable_any cv;
bool ready = false;
void worker(std::stop_token token)
{
std::unique_lock lock(mutex);
bool condition_met = cv.wait(
lock,
token,
[] {
return ready;
});
if (!condition_met)
{
// 没等到 ready == true,
// 而是因为停止请求结束等待
return;
}
// ready == true
}
This wait can be understood as:
等待两个条件中的任意一个:
1. ready == true
或者
2. 收到停止请求
If:
condition_met == true
Predicate representation:
ready == true
Established.
If:
condition_met == false
This indicates that the wait did not end because ready became true, but usually simply because a stop request was received.
In this way, even if the worker thread is waiting on the condition variable, it can respond to the stop protocol of jthread.
4.Selection and Common Errors
4.1.std::thread and std::jthread comparison
| Feature | std::thread |
std::jthread |
|---|---|---|
| Introduced version | C++11 | C++20 |
| Create thread | ✅ | ✅ |
Manual join() |
✅ | ✅ |
Manual detach() |
✅ | ✅ |
| Automatic cleanup on destruction | ❌ | ✅ |
Destructor handling in joinable state terminate() |
✅ | ❌ |
| Built-in stop request mechanism | ❌ | ✅ |
Automatically provided stop_token |
❌ | ✅ |
| Suitable for long-running stoppable worker | Generally | ✅ |
If the project can use C++20, for this kind of thread:
启动
↓
持续运行
↓
程序退出时请求停止
↓
安全结束
Usually prioritize:
std::jthread
4.2.atomic<bool> running and stop_token How to choose
Traditional code is often written like this:
std::atomic<bool> running{true};
void worker()
{
while (running.load())
{
// work
}
}
When stopped:
running.store(false);
This way of writing is fine.
For very simple threads, it is even quite intuitive.
For example:
running == true
→ 继续运行
running == false
→ 停止
However:
std::stop_token
Provided is a standardized shutdown protocol.
It can be used with:
std::jthread
std::stop_source
std::stop_callback
std::condition_variable_any
Direct coordination.
It can be understood as:
atomic<bool>
→ 只是一个线程安全的 bool
→ “true / false 到底是什么意思”由你自己规定
And:
stop_token
→ 专门表达“停止请求”
→ 标准库里的多个工具都认识这种协议
Therefore:
非常简单的开关
→ atomic<bool> 完全可以
明确的线程停止生命周期
→ jthread + stop_token 更合适
4.3.Common errors
4.3.1.Error: thought request_stop() would forcibly kill the thread
Misunderstanding:
request_stop()
→ 线程立刻消失
Correct understanding:
request_stop()
→ 发出停止请求
→ 工作线程自己检查并退出
4.3.2.Error: the worker never checks stop_requested()
For example:
void worker(std::stop_token)
{
while (true)
{
do_work();
}
}
Even if jthread automatic at destruction:
request_stop();
This thread will not exit either.
In the final destruction:
join();
Will always wait.
4.3.3.Error: Stop request checked, but blocked in the middle for too long
For example:
while (!token.stop_requested())
{
blocking_operation(); // 一卡几十秒
}
Although the stop request has already been issued, the thread must wait until the blocking operation returns before it can check again.
4.3.4.Error: used jthread and casually detach()
This will lose:
自动 join
自动停止请求
RAII 生命周期管理
These main advantages.
4.3.5.错误:在 stop_callback 里做大量复杂工作
callback is more suitable:
轻量通知
设置状态
唤醒等待者
rather than undertaking complex business logic.
4.3.6.Error: Assuming that receiving a stop request will immediately terminate the thread (important)
request_stop()It only issues a stop request and does not forcibly interrupt the worker thread.
Worker threads typically actively check at certainsafety checkpoints:
token.stop_requested()
For example:
while (!token.stop_requested())
{
finish_one_small_task();
}
If the stop request arrives exactly during the execution of finish_one_small_task() this function will not be forcibly terminated halfway through.
A thread will usually finish the current small chunk of work first, then return to the loop condition:
token.stop_requested()
After discovering the stop request, exit the loop and end the thread.
It can be understood as:
收到停止请求
↓
完成当前不能被随意打断的小任务
↓
到达安全检查点
↓
发现 stop_requested() == true
↓
退出循环
↓
完成必要的收尾
↓
线程结束
and join() only serves to:
Wait for this thread to actually finish.
So the typical relationship is:
request_stop()
→ 请求线程停止
worker 在安全位置响应请求并退出
join()
→ 等待 worker 退出完成
The so-called "appropriate, safe position" refers to a position where the thread state is already complete and resources are in a consistent state, such that exiting at this point will not leave behind half-completed operations.
Safepoint = the location where exit can begin; function return = the thread actually exits.
Therefore, it can be understood that the worker function in the example returning ≈ this thread has finished executing.
5.Summary
std::jthread It can be understood as:
With RAII lifetime management and a standard stop protocol
std::thread.
The most important points:
std::thread
→ 必须自己保证 join() / detach()
std::jthread
→ 析构时自动 request_stop() + join()
Stop mechanism:
request_stop()
→ 发出停止请求
stop_token.stop_requested()
→ 查看是否收到停止请求
It is:
协作式停止
rather than:
强制杀死线程
Additionally:
stop_source
→ 发出停止请求
stop_token
→ 观察停止请求
stop_callback
→ 停止请求出现时执行回调
For the background threads in C++20 that “run continuously after startup and need to stop safely on exit,” the general priority can be:
std::jthread + std::stop_token
rather than:
std::thread + 手写生命周期管理 + 自定义 atomic<bool> 停止协议