我不确定 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 中的编组接口指针(如果您的主thread 是一个 STA)- 因为我相信 CoMarshalInterThreadInterfaceInStream 可能会执行网络请求,所以您最好在 知道 客户端已连接时提前处理它,而不是冒着阻塞的风险你的主线程。