轮询取消令牌的异步代码与注册调用者请求时要执行的回调之间的根本区别是什么?

问题描述 投票:0回答:1

我正在观看(不是第一次)一般使用异步:C++ 执行器之旅(第 1 部分2,大约是 P2300

关于取消支持,Eric Niebler 表示调用代码应该声明一个

std::stop_source
,在其上调用
get_token()
,并将结果
std::stop_token
传递给要启动的异步代码。然后,呼叫者可以随时在 request_stop
 上拨打 
std::stop_source

异步代码的作者应该编写一些内容,以保证对该请求的迅速反应。埃里克说,要做到这一点,他们可以做以下两件事之一:

  1. 定期轮询由呼叫者提供的
    std::stop_token
    ,我假设是通过
    stop_requested()
    并做出相应反应,
  2. 或者通过注册在调用者请求停止时执行的回调。

虽然我可以很容易地想象解决方案 1,但我不太明白

  • 解决方案 2 会是什么样子,
  • 并且(也许这实际上与 P2300 无关,而是一般的异步性)为什么它会产生影响?毕竟,呼叫者请求停止”不是暗示在某处正在进行某种轮询吗?
    • 某处造成了差异吗?
c++ asynchronous concurrency cancellation
1个回答
1
投票

“解决方案 2 会是什么样子”。

“轮询”停止状态对于消耗 CPU 的线程来说是一件好事——它们在某个循环中计算某些内容,并且时不时地检查停止状态。到目前为止,一切都很好。

但是,线程不一定使用 CPU——它们可能处于等待调用状态,等待某些事情发生。这意味着他们无法轮询任何内容。不,您不想只是在 10 毫秒超时或类似的循环中运行等待,以便它可以检查停止状态。

在许多情况下,这实际上可能是某种事件循环。在这种情况下,在停止系统中注册的回调将用于向事件循环发送“退出”事件。

如果不使用事件循环,我们仍然可以通过从外部取消等待的方式来实现等待,然后由回调触发,允许线程唤醒并做出反应(通常只是抛出异常表示取消)。

事情也可以组合起来:您的回调可以简单地唤醒线程,并且线程将在寻找实际工作之前检查停止状态。这实际上取决于线程的作用和便利性。归根结底,回调适用于仅具有停止是/否布尔值还不够的情况,并且线程需要一些涉及踢的动作来注意到停止。

© www.soinside.com 2019 - 2024. All rights reserved.