2012-08-14 156 views
0

我有这种情况:异步完成处理

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

其中RequestsManager工作在异步方式:

  • sendRequest将放在一个队列并返回给调用者
  • 其他线程获取请求来自队列的请求并处理它们
  • 当处理一个请求时,回调被称为

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

回答

1

我可以看到一些方法如何实现它:

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

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

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

这会给你所有的告诫真正异步解决方案。它看起来像是目标线程执行被中断,执行跳入中断处理程序。在回调之前,目标线程需要被恢复。您将无法从回调内部访问线程本地存储或原始线程的堆栈。

3

否 - 调用/回调不能更改线程上下文 - 您必须发出一些信号以在线程之间进行通信。通常情况下,'someCallback'会或者发出发起'SendRequest'调用的线程正在等待的事件,(同步调用)或者推送SendRequest,(因此,可能是它的处理结果)到发送'SendRequest'调用的线程最终会弹出的队列上(异步)。这取决于发信人的信号是如何闪烁的。

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

1

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

经典的方式做到这一点是:

  • 在处理请求,RequestManager应该执行该&foo::someCallback
  • 避免阻塞请求管理器,你可能只是上升这里面的标志回调
  • 检查标志周期性的线程内,这被称为RequestsManager->SendRequest
  • 此标志将只是一个volatile boolclass foo

如果你想确保,调用线程(foo的)会立即明白,该request已被处理,则需要额外的同步。

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

  • foo的线程执行SendRequest
  • foo开始睡在一些select(例如)
  • RequestManager执行请求和:
    • 电话&foo::someCallback
    • “唤醒” foo的线程(通过发送文件描述符中的某个文件foo(使用select))
  • foo是唤醒
  • 检查volatile bool标志已经处理的请求
  • 做什么它需要做
  • 撤销本级标志