【问题标题】:How to pass jthread stop_token to functor?如何将 jthread stop_token 传递给仿函数?
【发布时间】:2021-12-05 17:32:26
【问题描述】:

我正在尝试使用新的 jthread 并已启动 std::jthread,其中确实调用了 operator(),但我无法让它停止。我想通过将其作为函数对象调用来创建线程。

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

如果我的 Test 类的 operater() 写成如下,它会编译:

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();
}   

但由于它没有停止,我想我需要以某种方式将std::stop_token 传递给class Test,就像这样。

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

但这不能编译。我也确实更改了标题。

/usr/lib/gcc/x86_64-pc-linux-gnu/10.3.0/include/g++-v10/thread: 在'static std::thread std::jthread::_S_create(std:: stop_source&, _Callable&&, _Args&& ...) [with _Callable = void (Test::)(std::stop_token); _Args = {测试}]': /usr/lib/gcc/x86_64-pc-linux-gnu/10.3.0/include/g++-v10/thread:450:28: 来自 'std::jthread::jthread(_Callable&&, _Args&& ...) [ with _Callable = void (Test::)(std::stop_token); _Args = {测试}; =无效]' /usr/lib/gcc/x86_64-pc-linux-gnu/10.3.0/include/g++-v10/bits/stl_construct.h:97:14: 来自'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: 来自'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::allocatorsstd::jthread]'

想法?

【问题讨论】:

    标签: c++ multithreading c++20


    【解决方案1】:

    您可以使用std::bind&amp;test绑定到&amp;Test::operator(),然后使用std::placeholders::_1为未绑定的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.

    正如@Nicol Bolas 所评论的,我们也可以使用C++20 std::bind_front 来做到这一点,这比std::bind 更轻量级和直观:

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

    【讨论】:

    【解决方案2】:

    一个简单有效的解决方案是使用 lambda:

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

    并节省额外的包括和图书馆设施

    Demo

    【讨论】:

      【解决方案3】:

      jthread(或thread,就此而言)接受任何可调用对象。这包括带有operator() 的任何内容,例如...Test

      默认是传值;使用 std::ref 通过引用传递,但请注意,在这种情况下,您需要确保被引用的对象比线程长。

      所以这只是:

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

      或(像您的原始代码一样通过引用传递):

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-22
        相关资源
        最近更新 更多