no estoy seguro sobre el sistema de ping DCOM, pero una opción para usted sería simplemente cultivar fuera de las notificaciones a un grupo de subprocesos por separado. Esto ayudará a mitigar el efecto de tener un pequeño número de clientes de bloqueo: empezarás a tener problemas cuando haya demasiados, por supuesto.
La forma más fácil de hacerlo es usar QueueUserWorkItem
- esto invocará la devolución de llamada pasada en el grupo de subprocesos del sistema de la aplicación. Suponiendo que estés usando un MTA, esto es todo lo que necesita hacer:
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);
}
Si el hilo principal se encuentra en una STA, esto es sólo un poco más compleja; sólo hay que utilizar CoMarshalInterThreadInterfaceInStream
y CoGetInterfaceAndReleaseStream
para pasar el puntero de interfaz entre apartamentos:
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);
}
Tenga en cuenta que la comprobación de errores ha sido eludido por claridad - que, por supuesto que desee error de comprobación de todas las llamadas - en particular, que desea verificar RPC_S_SERVER_UNAVAILABLE
y otros errores de red similares, y eliminar a los clientes infractores.
Algunas variaciones más sofisticadas que puede considerar incluyen asegurarse de que solo una solicitud está en vuelo por cliente a la vez (reduciendo aún más el impacto de un cliente atascado) y almacenar en caché el puntero de la interfaz ordenada en el MTA (si hilo principal es una STA) - ya que creo CoMarshalInterThreadInterfaceInStream
pueden realizar solicitudes de red, que le idealmente quiere cuidar de él antes de tiempo cuando se sabe el cliente está conectado, en lugar de correr el riesgo de bloqueo en el hilo principal.
¿Ha considerado enviar los eventos desde subprocesos de grupo de subprocesos para mitigar el bloqueo hasta cierto punto? – bdonlan
@bdonlan: Esa podría ser una solución, sin embargo, esto complicará significativamente el servidor: tendrá que encargarse de esos hilos adicionales de por vida. – sharptooth
No realmente; solo puede usar el grupo de subprocesos win32 incorporado. Si ya está usando un MTA, es bastante trivial pulsar QueueUserWorkItem. Si estás en una STA, deberías ordenar el control de la interfaz remota en el MTA, pero eso no es muy difícil de hacer con CoMarshalInterThreadInterfaceInStream, etc. – bdonlan