我不确定 DCOM ping 系统,但您的一种选择是简单地将通知转移到单独的线程池。这将有助于减轻拥有少量阻塞客户端的影响——当然,当有太多阻塞客户端时,您将开始遇到问题。
最简单的方法是使用QueueUserWorkItem
- 这将在应用程序的系统线程池上调用传递的回调。假设您使用的是 MTA,这就是您需要做的所有事情:
static InfoStruct {
IRemoteHost *pRemote;
BSTR someData;
};
static DWORD WINAPI InvokeClientAsync(LPVOID lpInfo) {
CoInitializeEx(COINIT_MULTITHREADED);
InfoStruct *is = (InfoStruct *)lpInfo;
is->pRemote->notify(someData);
is->pRemote->Release();
SysFreeString(is->someData);
delete is;
CoUninitialize();
return 0;
}
void InvokeClient(IRemoteHost *pRemote, BSTR someData) {
InfoStruct *is = new InfoStruct;
is->pRemote = pRemote;
pRemote->AddRef();
is->someData = SysAllocString(someData);
QueueUserWorkItem(InvokeClientAsync, (LPVOID)is, WT_EXECUTELONGFUNCTION);
}
如果您的主线程在 STA 中,这只会稍微复杂一些;您只需要使用CoMarshalInterThreadInterfaceInStream
并CoGetInterfaceAndReleaseStream
在公寓之间传递接口指针:
static InfoStruct {
IStream *pMarshalledRemote;
BSTR someData;
};
static DWORD WINAPI InvokeClientAsync(LPVOID lpInfo) {
CoInitializeEx(COINIT_MULTITHREADED); // can be STA as well
InfoStruct *is = (InfoStruct *)lpInfo;
IRemoteHost *pRemote;
CoGetInterfaceAndReleaseStream(is->pMarshalledRemote, __uuidof(IRemoteHost), (LPVOID *)&pRemote);
pRemote->notify(someData);
pRemote->Release();
SysFreeString(is->someData);
delete is;
CoUninitialize();
return 0;
}
void InvokeClient(IRemoteHost *pRemote, BSTR someData) {
InfoStruct *is = new InfoStruct;
CoMarshalInterThreadInterfaceInStream(__uuidof(IRemoteHost), pRemote, &is->pMarshalledRemote);
is->someData = SysAllocString(someData);
QueueUserWorkItem(InvokeClientAsync, (LPVOID)is, WT_EXECUTELONGFUNCTION);
}
请注意,为了清楚起见,已省略错误检查 - 您当然希望对所有调用进行错误检查 - 特别是,您希望检查RPC_S_SERVER_UNAVAILABLE
其他此类网络错误,并删除有问题的客户端。
您可能需要考虑一些更复杂的变体,包括确保每个客户端一次只有一个请求在进行中(从而进一步减少客户端卡住的影响)和缓存 MTA 中的编组接口指针(如果您的主线程是STA) - 因为我相信可能会执行网络请求,所以理想情况下,当您知道CoMarshalInterThreadInterfaceInStream
客户端已连接时,您最好提前处理它,而不是冒着阻塞主线程的风险。