multithreading - Múltiples hilos haciendo poll() o select() en un solo socket o tubería
sockets posix (3)
Acabo de encontrar un error debido a esta pregunta: tengo dos subprocesos seleccionados en el mismo socket, y llamaré a aceptar cuando el fd vuelva como isset (). De hecho, la selección regresa para ambos subprocesos, el fd isset () para ese fd en ambos subprocesos, y ambos subprocesos llaman aceptar (), uno gana y los otros bloques esperan que entre otra conexión.
Así que, de hecho, la selección volverá en todos los subprocesos que está bloqueando para el mismo fd.
¿Qué dicen POSIX y otros estándares sobre la situación en la que múltiples subprocesos realizan llamadas a poll()
o select()
en un solo socket o manejador de tubería al mismo tiempo?
Si llega algún dato, ¿solo uno de los hilos en espera se despierta o todos los hilos en espera se despiertan?
Pregunta interesante ... Leí el POSIX actual y no encontré una respuesta específica, es decir, ninguna especificación sobre invocaciones concurrentes. Entonces explicaré por qué creo que el estándar significa que todos se despertarán.
La parte relevante del text para select
/ select
es:
Al completarse con éxito, la función pselect () o select () modificará los objetos a los que apuntan los argumentos readfds, writefds y errorfds para indicar qué descriptores de archivo están listos para leer, listos para escribir, o tienen una condición de error pendiente, respectivamente , [...]
y después
Se considerará que un descriptor está listo para leer cuando una llamada a una función de entrada con O_NONBLOCK clear no se bloqueará, ya sea que la función transfiera o no los datos con éxito. (La función puede devolver datos, una indicación de fin de archivo o un error que no sea uno que indique que está bloqueada, y en cada uno de estos casos el descriptor se considerará listo para su lectura).
En resumen (solo el caso de lectura), podemos entender esto como:
select
no bloquea esto significa que la siguiente llamada a una función de entrada con O_NONBLOCK
no devolverá un error con errno==EWOULDBLOCK
. [Tenga en cuenta que el "siguiente" es mi interpretación de lo anterior.]
Si uno admite esta interpretación, entonces dos llamadas de select
simultáneas podrían devolver el mismo FD como legible. De hecho, incluso si no son concurrentes, pero una primera select
llamadas de subproceso con un FD se puede leer y más tarde, por ejemplo, una segunda select
llamada de subproceso entre las dos podría devolver el FD como legible para la segunda hebra.
Ahora la parte relevante para la parte de "despertar" de la pregunta es esta:
Si ninguno de los descriptores seleccionados está listo para la operación solicitada, la función pselect () o select () se bloqueará hasta que al menos una de las operaciones solicitadas esté lista, hasta que se agote el tiempo de espera o hasta que sea interrumpida por una señal.
Aquí claramente la interpretación anterior sugiere que todas las llamadas en espera que regresan al mismo tiempo volverán.
Todos deben activarse, todos deben devolver el mismo valor de resultado y todos deben hacer lo mismo con los conjuntos de FD. Todos están haciendo la misma pregunta, por lo que todos deberían obtener la misma respuesta.
Lo que se supone que debe hacer select()
, de acuerdo con la documentación POSIX que se ha citado aquí, y mis meros 25 años de experiencia con ella, es devolver el número de FD que se pueden leer, escribir, etc., en ese instante. Por lo tanto, sería completamente incorrecto que todas las llamadas select()
no concurrentes devuelvan lo mismo.
La función select()
no puede predecir el futuro, es decir, qué hilo realmente va a hacer una lectura o escritura, y por lo tanto, qué hilo tendrá éxito en eso. Ellos contienden. Es un problema de manada de truenos.