Я не уверен насчет системы проверки связи DCOM, но один из вариантов для вас - просто переключить уведомления в отдельный пул потоков.Это поможет смягчить эффект от небольшого количества блокирующих клиентов - хотя, конечно, их будет слишком много.
Самый простой способ сделать это - использовать 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
может выполнять сетевые запросы, в идеале вы бы хотели позаботиться об этом заранее, когда знаете, клиент подключен, вместо того, чтобы рисковать блокировкой в основном потоке.