Windows平台下C++中如何等待ExNotifyCallback的回调响应?
Windows下实现回调等待超时的标准方案
Windows平台下最标准的做法是使用**事件对象(Event)**实现同步等待,配合上下文结构体传递状态与数据,具体实现如下:
1. 定义上下文结构体
用于存储同步事件、回调返回的数据以及请求唯一标识(区分多实例响应):
typedef struct _RESPONSE_CONTEXT { HANDLE hEvent; // 同步事件句柄 void* pReceivedData; // 存储回调返回的数据 int dataSize; // 数据大小 UINT requestId; // 请求唯一标识,用于匹配对应实例的响应 } RESPONSE_CONTEXT, *PRESPONSE_CONTEXT;
2. 实现响应回调函数
在回调中校验请求标识,保存数据并触发事件通知等待线程:
void MyResponseFunc(void* pData, int* pDataSize) { PRESPONSE_CONTEXT pCtx = (PRESPONSE_CONTEXT)pData; // 替换为实际的请求ID校验逻辑,确保只处理当前等待的请求 if (pCtx->requestId == GetCurrentActiveRequestId()) { // 拷贝回调返回的数据(需根据实际场景处理内存分配与释放) pCtx->pReceivedData = malloc(*pDataSize); if (pCtx->pReceivedData != NULL) { memcpy(pCtx->pReceivedData, pData, *pDataSize); pCtx->dataSize = *pDataSize; } // 触发事件,通知等待线程响应已到达 SetEvent(pCtx->hEvent); } }
3. 主流程实现
调用ExNotifyCallback后等待事件触发,处理超时与成功场景:
BOOL SendRequestAndWait(void* pIn1, void* pIn2, void** ppOutData, int* pOutSize, DWORD timeoutMs) { BOOL result = FALSE; RESPONSE_CONTEXT ctx = {0}; UINT currentRequestId = GenerateUniqueRequestId(); // 生成唯一请求ID // 创建自动重置事件(触发后自动回到未触发状态,避免重复响应) ctx.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (ctx.hEvent == NULL) { return FALSE; } ctx.requestId = currentRequestId; // 将当前上下文绑定到响应回调(需根据实际场景实现,比如通过线程局部存储或ExNotifyCallback参数传递) BindResponseContext(&ctx); // 发送通知到监听实例 ExNotifyCallback(myCbObject, pIn1, pIn2); // 等待事件触发或超时 DWORD waitResult = WaitForSingleObject(ctx.hEvent, timeoutMs); switch (waitResult) { case WAIT_OBJECT_0: // 响应已到达,返回数据 *ppOutData = ctx.pReceivedData; *pOutSize = ctx.dataSize; result = TRUE; break; case WAIT_TIMEOUT: // 超时,清理已分配内存 if (ctx.pReceivedData != NULL) { free(ctx.pReceivedData); } result = FALSE; break; default: // 等待出错,清理资源 if (ctx.pReceivedData != NULL) { free(ctx.pReceivedData); } result = FALSE; break; } // 清理资源 CloseHandle(ctx.hEvent); UnbindResponseContext(); // 解除上下文绑定 return result; }
关键注意事项
- 线程安全:多实例并发场景下,必须通过
requestId严格匹配请求与响应,避免不同请求的回调互相干扰。 - 内存管理:回调中分配的内存需在主流程中正确释放,防止内存泄漏。
- 上下文传递:需确保响应回调能获取到当前请求的
RESPONSE_CONTEXT,可通过线程局部存储(TLS)、ExNotifyCallback参数传递或带锁的全局字典实现。 - 事件类型:使用自动重置事件可确保每次等待仅响应一次回调,避免后续误触发。
内容的提问来源于stack exchange,提问作者LalaWootwoot
相关产品推荐
相关产品推荐

