异步完成处理
Asynchronous Completion Handling
>我有这种情况:
void foo::bar()
{
RequestsManager->SendRequest(someRequest, this, &foo::someCallback);
}
其中 RequestsManager 以异步方式工作:
- 发送请求将请求放入队列并返回给调用方
- 其他线程从队列中获取请求并处理它们
- 处理一个请求时,将调用回调
是否可以在与 SendRequest 相同的线程中调用 foo::someCallback?如果没有,我如何避免遵循"回调限制":回调不应进行耗时的操作,以避免阻塞请求管理器。
调用/回调不能更改线程上下文 - 您必须发出一些信号才能在线程之间进行通信。
通常,"someCallback"会发出发出"SendRequest"调用的线程正在等待的事件的信号(同步调用),或者将SendRequest(因此,可能是其处理的结果)推送到队列中,发起"SendRequest"调用的线程最终将弹出(异步)。 只看发起人如何发出信号。.
Aynch 示例 - 回调可能 PostMessage/Dispatcher.Begin将已完成的 SendRequest 调用到 GUI 线程以显示结果。
我可以看到几种实现它的方法:
A) 实施类似于信号处理的策略
当请求处理结束时RequestManager
将回调调用放在等待列表中。下次调用SendRequest
时,在返回执行之前,它将检查线程是否有任何待处理的回调并执行它们。这是一种相对简单的方法,对客户端的要求最低。如果延迟不是问题,请选择它。 RequestManager
可以公开 API 以强制检查挂起的回调
B) 暂停回调目标线程并在第三个线程中执行回调
这将为您提供真正的异步解决方案及其所有注意事项。看起来目标线程执行被中断,执行跳转到中断处理程序。在回调返回之前,需要恢复目标线程。您将无法从回调内部访问线程本地存储或原始线程的堆栈。
取决于"耗时的操作"的定义。
执行此操作的经典方法是:
- 处理请求时,
RequestManager
应执行该&foo::someCallback
- 为了避免阻止请求管理器,您可以在此回调中举起一个标志
- 定期检查线程内部的该标志,该标志称为
RequestsManager->SendRequest
- 这面旗帜将只是
class foo
内部的一个volatile bool
如果要确保调用线程(foo
)立即理解,request
已被处理,则需要额外的同步。
在这些线程之间实现(或使用已经实现的)阻塞管道(或使用信号/事件)。这个想法是:
-
foo
的线程执行SendRequest
-
foo
开始睡在某个select
上(例如) -
RequestManager
执行请求并:- 呼叫
&foo::someCallback
- "唤醒"
foo
的线程(通过在该文件描述符中发送一些内容,foo
睡眠(使用select
))
- 呼叫
-
foo
觉醒了 - 检查已处理请求的
volatile bool
标志 - 做它需要做的事情
- 取消国旗
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- libcurl :C++处理多个异步请求
- 如何使用从处理程序调度的最终回调将响应异步返回给调用方on_read?
- 某些 boost::asio 异步函数是否将处理程序连接到操作,以便处理程序被触发一次?
- grpcc++异步服务器示例,在处理状态下是否需要互斥
- 窗口上信号处理程序的异步安全写入函数
- 异步操作的 Asio 处理程序在其同步对应项正常工作时不会调用
- 如何处理异步函数中的异常UWP应用程序getFileFrompathAsync(path);
- 如何在 TCP 侦听器中处理异步发送和接收
- 异步处理设备的高级线程用法
- 使用 boost::beast 异步处理流式 HTTP
- 使用多线程处理的异步请求
- boost::bind with member functions(作为boost::asio异步写入处理程序)
- C++-如何为同时/异步处理对文件进行分块
- 如何在Windows中进行正确的顺序异步消息处理
- 从asio处理程序生成新的异步请求
- 异步完成处理
- 处理多个std::异步调用
- 处理一个套接字和多个线程时异步 IO 的用例
- epoll或kqueue是否可以处理向其自身异步添加文件描述符