【问题标题】:Asynchronous Completion Handling异步完成处理
【发布时间】:2012-08-10 15:31:58
【问题描述】:

我有这种情况:

void foo::bar()
{
    RequestsManager->SendRequest(someRequest, this, &foo::someCallback);
}

RequestsManager 以异步方式工作的地方:

  • SendRequest 将请求放入队列并返回给调用者
  • 其他线程从队列中获取请求并处理它们
  • 当一个请求被处理时,回调被调用

是否可以在与 SendRequest 相同的线程中调用 foo::someCallback?如果没有,我该如何避免遵循“回调限制”:回调不应进行耗时的操作以避免阻塞请求管理器。

【问题讨论】:

    标签: c++ multithreading asynchronous


    【解决方案1】:

    否 - 调用/回调不能更改线程上下文 - 您必须发出一些信号才能在线程之间进行通信。

    通常,“someCallback”会发出一个事件信号,在该事件上发起“SendRequest”调用的线程正在等待(同步调用),或者推送 SendRequest,(因此,大概是其处理的结果),到一个队列上,发起“SendRequest”调用的线程最终将弹出,(异步)。只是取决于如何向发起者发出信号。..

    Aynch 示例 - 回调可能 PostMessage/Dispatcher.BeginInvoke 完成的 SendRequest 到 GUI 线程以显示结果。

    【讨论】:

      【解决方案2】:

      我可以看到几种方法来实现它:

      A) 实施类似于信号处理的策略

      当请求处理结束时RequestManager 将回调调用放在等待列表中。下次调用SendRequest 时,在返回执行之前,它将检查线程是否有任何挂起的回调并执行它们。这是一种相对简单的方法,对客户端的要求最低。如果延迟不是问题,请选择它。 RequestManager 可以公开 API 以强制检查挂起的回调

      B) 挂起回调目标线程并在第三个线程中执行回调

      这将为您提供 true 异步解决方案及其所有注意事项。看起来目标线程执行被中断并且执行跳转到中断处理程序。在回调返回之前,需要恢复目标线程。您将无法从回调内部访问线程本地存储或原始线程的堆栈。

      【讨论】:

        【解决方案3】:

        取决于“耗时操作”的定义。

        执行此操作的经典方法是:

        • 当请求被处理时,RequestManager 应该执行那个&foo::someCallback
        • 为避免阻塞请求管理器,您可以在此回调中升旗
        • 在线程内定期检查该标志,称为RequestsManager->SendRequest
        • 此标志将只是 volatile bool 内的 class foo

        如果您想确保调用线程 (foo's) 将立即了解 request 已被处理,您需要额外的同步。

        在这些线程之间实现(或使用已实现的)阻塞管道(或使用信号/事件)。这个想法是:

        • foo的线程执行SendRequest
        • foo 开始在某些 select 上睡觉(例如)
        • RequestManager 执行请求并且:
          • 致电&foo::someCallback
          • “唤醒”foo 的线程(通过在该文件描述符中发送一些内容,foo 休眠(使用 select))
        • foo被唤醒
        • 检查volatile bool 标志是否已处理请求
        • 做它需要做的事情
        • 取消标志

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-01-13
          • 2023-03-25
          • 1970-01-01
          • 2022-01-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多