Sto scrivendo un server multi-threaded POSIX compatibile in c/C++ che deve essere in grado di accettare, leggere e scrivere su un numero elevato di connessioni in modo asincrono. Il server ha diversi thread di lavoro che eseguono attività e, occasionalmente (e in modo imprevedibile), i dati delle code da scrivere nei socket. I dati sono anche occasionalmente (e imprevedibilmente) scritti sui socket dai client, quindi il server deve anche leggere in modo asincrono. Un modo ovvio per fare questo è dare a ciascuna connessione un thread che legge e scrive da/verso il suo socket; questo è brutto, tuttavia, dal momento che ogni connessione può persistere per un lungo periodo di tempo e il server potrebbe quindi dover contenere centinaia o migliaia di thread solo per tenere traccia delle connessioni.In attesa di una condizione (pthread_cond_wait) e un cambio di socket (selezionare) simultaneamente
Un approccio migliore sarebbe avere un singolo thread che gestisse tutte le comunicazioni usando le funzioni select()/pselect(). Ad esempio, un singolo thread attende che qualsiasi socket sia leggibile, quindi genera un lavoro per elaborare l'input che verrà gestito da un pool di altri thread ogni volta che l'input è disponibile. Ogni volta che gli altri thread di lavoro producono output per una connessione, vengono messi in coda e il thread di comunicazione attende che tale socket sia scrivibile prima di scriverlo.
Il problema con questo è che il thread di comunicazione potrebbe essere in attesa nella funzione select() o pselect() quando l'output viene accodato dai thread worker del server. È possibile che, se nessun input arriva per diversi secondi o minuti, un chunk di output in coda attende solo che il thread di comunicazione sia terminato select() ing. Questo non dovrebbe accadere, tuttavia, i dati dovrebbero essere scritti il prima possibile.
In questo momento vedo un paio di soluzioni a questo thread-safe. Uno è quello di avere il thread di comunicazione occupato - attendere l'input e aggiornare l'elenco di socket su cui attende per scrivere ogni decimo di secondo. Questo non è ottimale poiché implica l'attesa, ma funzionerà. Un'altra opzione è quella di usare pselect() e inviare il segnale USR1 (o qualcosa di equivalente) ogni volta che un nuovo output è stato accodato, consentendo al thread di comunicazione di aggiornare immediatamente l'elenco di socket in attesa di uno stato scrivibile. Preferisco quest'ultimo, ma non mi piace usare un segnale per qualcosa che dovrebbe essere una condizione (pthread_cond_t). Un'altra opzione sarebbe quella di includere, nell'elenco dei descrittori di file su cui select() è in attesa, un file fittizio che scriviamo un singolo byte ogni volta che un socket deve essere aggiunto al fd_set scrivibile per select(); ciò riattiverebbe il server di comunicazione perché quel particolare file fittizio sarebbe quindi leggibile, consentendo in tal modo al thread di comunicazione di aggiornare immediatamente il proprio fd_set scrivibile.
Mi sembra intuitivo, che il secondo approccio (con il segnale) è il modo "più corretto" per programmare il server, ma sono curioso se qualcuno sa o quale di questi è il più efficiente, in generale, se uno dei due sopra causerà condizioni di gara di cui non sono a conoscenza, o se qualcuno conosce una soluzione più generale a questo problema. Quello che voglio veramente è una funzione pthread_cond_wait_and_select() che consente al thread di comunicazione di attendere sia una modifica dei socket che un segnale da una condizione.
Grazie in anticipo.