La función WaitNamedPipe
permite que una aplicación de cliente de tubería espere sincrónicamente una conexión disponible en un servidor de canalización con nombre. Luego, llama al CreateFile
para abrir el conducto como cliente. Pseudocódigo:¿Qué es una alternativa de E/S superpuesta a WaitNamedPipe?
// loop works around race condition with WaitNamedPipe and CreateFile
HANDLE hPipe;
while (true) {
if (WaitNamedPipe says connection is ready) {
hPipe = CreateFile(...);
if (hPipe ok or last error is NOT pipe busy) {
break; // hPipe is valid or last error is set
}
} else {
break; // WaitNamedPipe failed
}
}
El problema es que todas estas son llamadas de bloqueo y síncronas. ¿Cuál es una buena manera de hacer esto de forma asíncrona? Parece que no puedo encontrar una API que use E/S superpuestas para hacer esto, por ejemplo. Por ejemplo, para los servidores de tubería , la función ConnectNamedPipe
proporciona un parámetro lpOverlapped
que permite a un servidor esperar asíncronamente a un cliente. El servidor de tuberías puede llamar al WaitForMultipleObjects y esperar a que se complete la operación de E/S o que se marque cualquier otro evento (por ejemplo, un evento que indica el hilo para cancelar la E/S pendiente y terminar).
La única forma en que se me ocurre es llamar al WaitNamedPipe
en un bucle con un tiempo de espera corto y finito y verificar otras señales si se agota el tiempo. Alternativamente, en una llamada de bucle CreateFile
, verifique otras señales y luego llame al Sleep
con un breve retraso (o WaitNamedPipe
). Por ejemplo:
HANDLE hPipe;
while (true) {
hPipe = CreateFile(...);
if (hPipe not valid and pipe is busy) {
// sleep 100 milliseconds; alternatively, call WaitNamedPipe with timeout
Sleep(100);
// TODO: check other signals here to see if we should abort I/O
} else
break;
}
Pero este método apesta al cielo en mi opinión. Si un tubo no está disponible por un tiempo, el hilo continúa funcionando: chupando CPU, usando energía, requiriendo que las páginas de memoria permanezcan en RAM, etc. En mi opinión, un hilo que se basa en Sleep
o corto tiempo de espera no funciona bien y es un signo de programación descuidada de múltiples hilos.
¿Pero cuál es la alternativa en este caso?
Una solución obvia es poner la llamada a WaitNamedPipe en un hilo separado. IIRC, varias de las funciones asíncronas de IO en realidad usan subprocesos bajo el capó, por lo que esto no es tan ineficiente como parece. –
Cuéntanos más acerca de la condición de carrera que este código está trabajando. El código de cliente de muestra de la documentación de MS dice que primero llame a CreateFile y solo llama a WaitNamedPipe si Create falla con Pipe Ocupado. Hazlo en un bucle, con un tiempo de espera apropiado en Espera. Eso siempre ha funcionado en mi experiencia. El error solo ocurre cuando dos clientes van por una tubería, pero no es una carrera. Un cliente se conecta, y el otro espera y vuelve a intentar, que es lo mismo que sucede con su ejemplo de suspensión, pero más limpio. –
@Mark: está en la documentación. Cuando WaitNamedPipe tiene éxito, CreateFile aún puede fallar porque otro hilo saltó primero. Esa es una condición de carrera: dos o más hilos están corriendo para abrir la tubería. Poner el lazo en funciona alrededor de la condición de carrera, de ahí el comentario en el código OPs. Sin embargo, ese no es el problema que nos está pidiendo que solucionemos. –