简体   繁体   English

C++20 使用 std::stop_token 停止分离的 std::jthread

[英]C++20 stopping a detached std::jthread using an std::stop_token

In C++20 std::jthread was introduced as a safer version of std::thread ;在 C++20 中, std::jthread被引入为std::thread的更安全版本; where std::jthread , as far as I understand, cleans up after itself when the thread exits.据我了解,其中std::jthread会在线程退出时自行清理。

Also, the concept of cooperative cancellation is introduced such that an std::jthread manages an std::stop_source that handles the state of the underlying thread, this std::stop_source exposes an std::stop_token that outsiders can use to read the state of the thread sanely.此外,引入了协作取消的概念,以便std::jthread管理一个处理底层线程状态的std::stop_source ::stop_source ,这个std::stop_source公开了一个std::stop_token ,外人可以使用它来读取状态线程的理智。

What I have is something like this.我所拥有的是这样的。

class foo {
  std::stop_token stok;
  std::stop_source ssource;

public:
  void start_foo() {
    // ...
    auto calculation = [this](std::stop_token inner_tok) {
      // ... (*this is used here)
      while(!inner_tok.stop_requested()) {
        // stuff
      }
    }
    auto thread = std::jthread(calculation);
    ctok = thread.get_stop_token();
    ssource = thread.get_stop_source();

    thread.detach(); // ??
  }

  void stop_foo() {
    if (ssource.stop_possible()) {
      ssource.request_stop();
    }
  }

  ~foo() {
   stop_foo();
  }
}

Note foo is managed by a std::shared_ptr , and there is no public constructor.注意foostd::shared_ptr管理,并且没有公共构造函数。

Somewhere along the line, another thread can call foo::stop_foo() on a possibly detached thread.沿着这条线的某个地方,另一个线程可以在可能分离的线程上调用foo::stop_foo()

Is what I am doing safe?我所做的安全吗?

Also, when detaching a thread, the C++ handle is no longer associated with the running thread, and the OS manages it, but does the thread keep receiving stop notifications from the std::stop_source ?此外,在分离线程时,C++ 句柄不再与正在运行的线程关联,由操作系统管理,但线程是否继续从std::stop_source接收停止通知?

Is there a better way to achieve what I need?有没有更好的方法来实现我所需要的? In MVSC, this doesn't seem to raise any exceptions or halt program execution, and I've done a lot of testing to verify this.在 MVSC 中,这似乎不会引发任何异常或停止程序执行,我已经做了很多测试来验证这一点。

So, is this solution portable?那么,这个解决方案是否可移植?

What you wrote is potentially unsafe if the thread accesses this after the foo has been destroyed.如果线程在foo被销毁后访问this ,那么您编写的内容可能是不安全的。 It's also a bit convoluted.这也有点令人费解。 A simpler approach would just be to stick the jthread in the structure...一种更简单的方法是将jthread粘贴在结构中......

class foo {
  std::jthread thr;

public:
  void start_foo() {
    // ...
    jthr = std::jthread([this](std::stop_token inner_tok) {
      // ... (*this is used here)
      while(!inner_tok.stop_requested()) {
        // stuff
      }
    });
  }

  void stop_foo() {
    jthr.request_stop();
  }

  ~foo() {
     stop_foo();
     // jthr.detatch(); // this is a bad idea
  }
}

To match the semantics of your code, you would uncomment the jthr.detach() in the destructor, but this is actually a bad idea since then you could end up destroying foo while the thread is still accessing it.为了匹配代码的语义,您可以在析构函数中取消注释jthr.detach() ,但这实际上是一个坏主意,因为那时您最终可能会在线程仍在访问它时销毁foo The code I wrote above is safe, but obviously whichever thread drops the last reference to the foo will have to wait for the jthread to exit.我上面写的代码是安全的,但是很明显,无论哪个线程删除了对foo的最后一个引用,都必须等待jthread退出。 If that's really intolerable, then maybe you want to change the API to stick a shared_ptr in the thread itself, so that the thread can destroy foo if it is still running after the last external reference is dropped.如果这真的令人无法忍受,那么也许您想更改 API 以在线程本身中粘贴一个shared_ptr ,这样如果在删除最后一个外部引用后线程仍在运行,则该线程可以销毁foo

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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