C++20 jthread stop_token 사용법, 스레드 취소를 어떻게 하나

C++20’s std::jthread automatically calls join() on destruction and carries an internal std::stop_source, so it can hand out a cooperative cancellation signal alongside the thread itself. This note stays narrow: only the auto-join behavior and how to pass and check a stop_token, based on cppreference.

It does not re-explain atomic or RAII fundamentals — only how jthread hooks into stop_token for cancellation.

What sets jthread apart from a plain thread?

Short answer: It joins automatically on destruction and carries a built-in std::stop_source for cooperative cancellation.

A std::thread calls std::terminate if it is destroyed without an explicit join() or detach() call first. Across multiple return paths or exception cases, remembering that call every time is easy to miss.

std::jthread calls join() in its own destructor. The moment the object leaves scope, the running thread is cleaned up safely, removing the class of bugs caused by a forgotten join.

Each jthread instance also holds an internal std::stop_source state from the moment it is created. That state is what lets external code call request_stop() later to ask the thread to cancel.

std::jthread worker([](std::stop_token st) {
    while (!st.stop_requested()) {
        // do work
    }
});
// join() runs automatically when worker goes out of scope

How does a stop_token reach the thread body?

Short answer: Declare std::stop_token as the first parameter of the callable, and jthread injects it automatically at launch.

Cancellation starts outside the thread: calling request_stop() on the jthread object.

To receive that request, the thread’s work routine — a lambda or a function — must accept a std::stop_token as its first argument. jthread passes this token in automatically when it starts the thread.

Inside the loop, poll stop_token.stop_requested() regularly and return once it evaluates to true, so the thread exits cleanly instead of being forced down.

void run(std::stop_token st) {
    while (!st.stop_requested()) {
        // loop body
    }
    // clean up, then return
}

std::jthread t(run);
t.request_stop();

If cancellation doesn’t take effect, what should you check?

Short answer: Confirm the loop polls stop_requested() often enough, and that blocking waits use condition_variable_any.

stop_token is cooperative, not a forced kill. If the thread never checks the flag and never returns on its own, the cancellation request is simply ignored.

If the loop contains a long-running heavy step, add checkpoints that call stop_requested() between segments. Sparse checkpoints mean cancellation is only noticed long after the request was made.

Also check whether the thread is sitting in a blocking I/O call or a condition-variable wait. To build an interruptible wait around a stop_token, use std::condition_variable_any instead of the plain std::condition_variable.

CheckWhat to verify
Poll frequencyDoes the loop call stop_requested() often enough?
Blocking waitIs the wait built on condition_variable_any so it can be interrupted?
Cancellation modelDoes the thread return on its own instead of expecting a forced kill?

For an immediate reaction, registering a std::stop_callback runs a callback right when the stop request is made.

Sources