Escribo un servidor multihebra compatible con POSIX en c/C++ que debe poder aceptar, leer y escribir en una gran cantidad de conexiones asincrónicamente El servidor tiene varios subprocesos de trabajo que realizan tareas y ocasionalmente (e impredeciblemente) datos de cola para escribir en los sockets. Los clientes también escriben ocasionalmente (e impredeciblemente) datos en los sockets, por lo que el servidor también debe leer de forma asincrónica. Una forma obvia de hacerlo es dar a cada conexión un hilo que lea y escriba desde/hasta su socket; sin embargo, esto es feo, ya que cada conexión puede persistir durante mucho tiempo y, por lo tanto, el servidor puede tener que contener cientos o miles de hilos solo para realizar un seguimiento de las conexiones.Esperando una condición (pthread_cond_wait) y un cambio de socket (seleccionar) simultáneamente
Un mejor enfoque sería tener un solo hilo que manejara todas las comunicaciones utilizando las funciones select()/pselect(). Es decir, un único subproceso espera que cualquier socket sea legible, luego genera un trabajo para procesar la entrada que será manejada por un conjunto de otros subprocesos siempre que la entrada esté disponible. Cada vez que los otros subprocesos de trabajo producen salida para una conexión, se pone en cola, y el subproceso de comunicación espera que ese socket sea grabable antes de escribirlo.
El problema con esto es que el hilo de comunicación puede estar esperando en la función select() o pselect() cuando la salida está en cola por los subprocesos de trabajo del servidor. Es posible que, si no llega ninguna entrada durante varios segundos o minutos, un fragmento de salida en cola simplemente esperará a que se complete el hilo de comunicación select() ing. Esto no debería suceder, sin embargo, los datos deben escribirse lo antes posible.
Ahora mismo veo un par de soluciones que son seguras para subprocesos. Una de ellas es tener el hilo de comunicación ocupado: espere la entrada y actualice la lista de tomas que espera para escribir cada décima de segundo aproximadamente. Esto no es óptimo ya que implica esperar ocupado, pero funcionará. Otra opción es usar pselect() y enviar la señal USR1 (o algo equivalente) siempre que se haya puesto en cola la salida nueva, permitiendo que el hilo de comunicación actualice la lista de sockets que está esperando para el estado de escritura inmediatamente. Prefiero este último aquí, pero todavía no me gusta usar una señal para algo que debería ser una condición (pthread_cond_t). Otra opción más sería incluir, en la lista de descriptores de archivos en los que está esperando select(), un archivo ficticio en el que escribamos un solo byte cada vez que se necesite agregar un socket al fd_set escribible para select(); esto despertaba el servidor de comunicaciones porque ese archivo ficticio particular sería entonces legible, lo que permite que el hilo de comunicaciones actualice inmediatamente su escritura fd_set.
Siento intuitivamente que el segundo enfoque (con la señal) es la forma "más correcta" de programar el servidor, pero tengo curiosidad si alguien sabe cuál de los anteriores es el más eficiente, en términos generales, si alguno de los anteriores causará condiciones de carrera que no conozco, o si alguien sabe de una solución más general a este problema. Lo que realmente quiero es una función pthread_cond_wait_and_select() que permita que el hilo de comunicación espere un cambio en los sockets o una señal de una condición.
Gracias de antemano.