ASIO计时器`cancel()`可以称之为虚假的“成功”吗?

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

ASIO documentation for basic_deadline_timer::cancel()有以下评论部分:

如果在调用cancel()时计时器已经过期,那么异步等待操作的处理程序将:

  • 已被调用;要么
  • 已经在不久的将来排队等待调用。

这些处理程序不能再被取消,因此传递一个错误代码,指示等待操作的成功完成。

我强调了这一点。通常,当您在计时器上调用cancel()时,将使用错误代码“用户取消操作”运行回调。但是这表示用成功错误代码实际调用它的可能性很小。我认为它试图说可能发生以下情况:

  1. 线程A在计时器上调用async_wait(myTimerHandler),其中myTimerHandler()是用户回调函数。
  2. 线程B调用io_context::post(cancelMyTimer),其中cancelMyTimer()是用户回调函数。现在排队等待在线程A中调用。
  3. 计时器截止时间到期,因此ASIO将计时器回调处理程序排队,并显示成功错误代码。它还没有调用它,但它排队等候在线程A中调用。
  4. ASIO在线程A中调用cancelMyTimer(),在计时器上调用cancel()。但是计时器已经被触发,并且ASIO没有检查处理程序是否仍然排队并且没有执行,所以这没有做任何事情。
  5. ASIO现在调用myTimerHandler,并且在此期间不检查cancel()是否被调用,因此它仍然成功通过错误代码。

请记住,这个例子只有一个线程调用io_context::run()deadline_timer::async_waitdeadline_timer::cancel()。在另一个线程中发生的唯一事情是调用post(),这是为了避免任何竞争条件。这一系列活动是否可行?或者它是指一些多线程场景(鉴于定时器不是线程安全的,这似乎不太可能)?

上下文:如果你有一个你希望定期重复的计时器,那么显而易见的事情就是检查回调中的错误代码,如果代码成功则再次设置计时器。如果可以进行上述竞赛,则需要有一个单独的变量来说明你是否取消了计时器,除了调用cancel()之外你还更新了计时器。

timer boost-asio
1个回答
1
投票

你陈述的一切都是正确的。因此,在您的情况下,您可能需要一个单独的变量来指示您不想继续循环。我通常使用atomic_bool并且我不打扰发布取消例程,我只是设置bool和调用取消来自我所在的任何线程。

更新:

我的答案的来源主要是使用ASIO多年的经验以及了解asio代码库足以解决问题并在需要时扩展其部分内容。

是的文档说它在deadline_timer的共享实例之间不是线程安全的,但文档不是最好的(文档是什么......)。如果您查看“取消”如何工作的来源,我们可以看到:

Boost Asio版本1.69:boost \ asio \ detail \ impl \ win_iocp_io_context.hpp

template <typename Time_Traits>
std::size_t win_iocp_io_context::cancel_timer(timer_queue<Time_Traits>& queue,
    typename timer_queue<Time_Traits>::per_timer_data& timer,
    std::size_t max_cancelled)
{
  // If the service has been shut down we silently ignore the cancellation.
  if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
    return 0;

  mutex::scoped_lock lock(dispatch_mutex_);
  op_queue<win_iocp_operation> ops;
  std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
  post_deferred_completions(ops);
  return n;
}

您可以看到取消操作由互斥锁保护,因此“取消”操作是线程安全的。

在截止时间计时器上调用大多数其他操作不是(关于从多个线程同时调用它们)。

另外我认为你对快速排序的计时器重启是正确的。我通常没有用这种方式停止和启动计时器的用例,所以我从来不需要这样做。

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