How do you use std::jthread::get_stop_token()?
Asked Answered
D

2

6

I'm confused how std::jthread::get_stop_token is designed to work, because it seems to have an inherent race condition.

Namely, the executing thread can't simply call std::jthread on itself (as in this example) because it has no guarantee that the std::jthread object is actually constructed by the time that it begins executing. It seem to me that for a thread to use its own get_stop_token, it requires (at the very least) an extra event (like std::latch) solely to synchronize against its own construction.

However, I do not see any examples or mentions of this issue online, and so it seems to me that this may not be the intended usage. It does seem rather clunky and error-prone, as well as potentially inefficient as it requires the worker thread to block on the main thread before proceeding.

So how is get_stop_token supposed to be used?
Is there a simple example of the proper, intended usage of std::jthread::get_stop_token()?

Donovan answered 22/4, 2021 at 8:5 Comment(3)
In my opinion, it is used to know outside the thread when a stop is requested. for example in a third thread :)Confounded
The question is based on a false premise. The jthread object is too guaranteed to be fully constructed by the time the thread function begins executing: "[thread.jthread.cons]/7 Synchronization: The completion of the invocation of the constructor synchronizes with the beginning of the invocation of the copy of f."Rebecarebecca
@IgorTandetnik: Thanks, that seems like a great thing to post in an answer as well.Donovan
B
3

It appears from the example from here that get_stop_token is actually not meant to be used by the client code. It is called behind the scenes by the std::jthread and passed to the function called by std::jthread. It appears it is the way it's got to be done

#include <thread>
#include <iostream>
 
void f(std::stop_token stop_token, int value)
{
    while (!stop_token.stop_requested()) {
    }
}
 
int main()
{
    std::jthread thread(f, 5); 
}
Brno answered 22/4, 2021 at 8:19 Comment(3)
Yes, it seems that std::jthreads constructor detects if the function is invokable with a std::stop_token: en.cppreference.com/w/cpp/thread/jthread/jthreadNarceine
Ahh! That explains it, thanks! I guess (as someone suggested above) they probably exposed it so that outsiders can check cancellation too?Donovan
The documentation/examples on cppreference is not very clear. I had no idea the stop_token should be 'implicit' to make the automatic destruction work properly. If you pass the stop_token explicitly, there's no automatic stopping.Tippett
P
0

The problem in the example and in the accepted answer from that question is that the line j1 = std::jthread(&JT::init, this, std::stop_token()); involves a constructor and move operator, the second one concurring with auto st = j1.get_stop_token();. This can be fixed by using the constructor initializer list, which will not call the additional move operator:

JT() : j1(std::jthread(&JT::init, this)) {
}

Thanks to igor-tandetnik for clarifying that jthread object is guaranteed to be fully constructed by the time the thread function begins executing and suggesting the answer at my related question.

Publican answered 24/2, 2023 at 15:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.