Skip to content
C++ Basics: Stop a std::jthread Cooperatively

C++ Basics: Stop a std::jthread Cooperatively

November 2, 2026

Combine a stop-aware condition-variable wait with a readiness handshake and join before reading the result.

Prepare a scratch directory

Tested on Linux x86_64 with GCC 14.2.0. Install a C++20-capable GCC compiler and its standard-library development files, with g++ on PATH. You also need Bash, a text editor, and mktemp, rm, and rmdir. No third-party library is required.

Keep the same terminal open. Stop if setup fails before saving the source:

start_directory="$PWD"
work_directory="$(mktemp -d)" || exit 1
cd -- "$work_directory" || exit 1

Run the example

Save this as jthread-cooperative-stop-demo.cpp:

#include <condition_variable>
#include <future>
#include <iostream>
#include <mutex>
#include <stop_token>
#include <thread>

int main()
{
    std::mutex work_mutex;
    std::condition_variable_any work_changed;
    std::promise<void> ready_promise;
    auto ready = ready_promise.get_future();
    bool observed_stop = false;
    std::jthread worker([&](std::stop_token stop_token) {
        std::unique_lock lock(work_mutex);
        ready_promise.set_value();
        work_changed.wait(lock, stop_token, [] { return false; });
        observed_stop = stop_token.stop_requested();
    });
    ready.wait();
    const bool accepted = worker.request_stop();
    worker.join();
    std::cout << std::boolalpha
              << "Request accepted: " << accepted << '\n'
              << "Worker observed stop: " << observed_stop << '\n';
}

Compile and run it. The second command runs only after compilation succeeds:

g++ -std=c++20 -Wall -Wextra -Werror -pedantic -pthread jthread-cooperative-stop-demo.cpp -o jthread-cooperative-stop-demo &&
./jthread-cooperative-stop-demo

Observed output:

Request accepted: true
Worker observed stop: true

Read the result

The future confirms that the worker reached its ready point. The predicate intentionally remains false, so the stop-aware wait returns when cancellation is requested. A request made just before the worker begins waiting also works: the stop state is retained. join completes before main reads observed_stop, so no atomic is needed for that final read.

Apply it carefully

Cancellation is cooperative, not a forced thread kill. A worker doing computation must check its token, and an ordinary blocking operation may not respond to it. A joinable jthread destructor requests stop and joins, but a worker that ignores cancellation can still delay destruction. This demonstration has no actual work queue; use a real readiness predicate in an application.

The C++ working draft documents the relevant behavior. This example uses C++20 features, not newer additions shown elsewhere in the current draft.

Clean up

Remove only the source and executable created here, then remove the empty practice directory:

rm -- jthread-cooperative-stop-demo.cpp jthread-cooperative-stop-demo
cd -- "$start_directory" || exit 1
rmdir -- "$work_directory"
unset start_directory work_directory

If the directory is not empty, inspect its remaining contents before removing anything else.

Acknowledgements

This post was created with assistance from AI.

Last updated on