简体   繁体   中英

How to pass jthread stop_token to functor?

I'm trying to work with the new jthreads and have started a std::jthread where the operator() does get called, but I am unable to get it to stop. I want to create the thread by calling it as a function object.

my_thrd = std::make_shared<std::jthread>(&Test::operator(), &test);

If operater() of my Test class is written as the following, it compiles:

void Test::operator()()
{
    using namespace std::literals;
    
    while (!token.stop_requested()) {
        std::cout << "Working ...\n" << std::flush;

        std::this_thread::sleep_for(5s);
    }   
    
    close_connection();
}   

But since it wasn't stopping, I thought I needed to somehow pass std::stop_token to class Test , like so.

void Test::operator()(std::stop_token token) { ... }

But this doesn't compile. I did change the header as well.

/usr/lib/gcc/x86_64-pc-linux-gnu/10.3.0/include/g++-v10/thread: In instantiation of 'static std::thread std::jthread::_S_create(std::stop_source&, _Callable&&, _Args&& ...) [with _Callable = void (Test:: )(std::stop_token); _Args = {Test }]': /usr/lib/gcc/x86_64-pc-linux-gnu/10.3.0/include/g++-v10/thread:450:28: required from 'std::jthread::jthread(_Callable&&, _Args&& ...) [with _Callable = void (Test:: )(std::stop_token); _Args = {Test }; = void]' /usr/lib/gcc/x86_64-pc-linux-gnu/10.3.0/include/g++-v10/bits/stl_construct.h:97:14: required from 'constexpr decltype (::new(void*(0)) _Tp) std::construct_at(_Tp*, _Args&& ...) [with _Tp = std::jthread; _Args = {void (Test:: )(std::stop_token), Test }; decltype (::new(void*(0)) _Tp) = std::jthread*]' /usr/lib/gcc/x86_64-pc-linux-gnu/10.3.0/include/g++-v10/bits/alloc_traits.h:514:4: required from 'static constexpr void std::allocator_traitsstd::allocator<_CharT >::construct(std::allocator_traitsstd::allocator<_CharT >::allocator_type&, _Up*, _Args&& ...) [with _Up = std::jthread; _Args = {void (Test:: )(std::stop_token), Test }; _Tp = std::jthread; std::allocator_traitsstd::allocator<_CharT >::allocator_type = std::allocatorstd::jthread]'

Thoughts?

You can usestd::bind to bind &test to &Test::operator() , then use std::placeholders::_1 to reserve a place for unbound std::stop_token :

struct Test {
  void operator()(std::stop_token token) {
    using namespace std::literals;
    while (!token.stop_requested()) {
      std::cout << "Working ...\n" << std::flush;
      std::this_thread::sleep_for(5s);
    }
  }
};

int main() {
  Test test;
  auto my_thrd = std::make_shared<std::jthread>(
    std::bind(&Test::operator(), &test, std::placeholders::_1));
}

Demo.

As @Nicol Bolas commented, we can also use C++20std::bind_front to do this, which is more lightweight and intuitive than std::bind :

auto my_thrd = std::make_shared<std::jthread>(
    std::bind_front(&Test::operator(), &test));

A simple, efficient solution is to use a lambda:

auto my_thrd = std::make_shared<std::jthread>(
  [&test] (std::stop_token token) { test(token); });

and spare the extra includes and library facilities

Demo

jthread (or thread , for that matter) accepts any callable object. That includes anything with an operator() , like... Test .

The default is to pass by value; use std::ref to pass by reference, but note that you are on the hook for ensuring that the referenced object outlives the thread in that case.

So this is just:

auto my_thrd = std::make_shared<std::jthread>(test);

or (to pass by reference like your original code):

auto my_thrd = std::make_shared<std::jthread>(std::ref(test));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM