Ogni volta che si utilizza un'architettura basata sugli eventi, è necessario disporre di un unico meccanismo per segnalare il completamento dell'evento. Su Linux, se si utilizzano i file, è necessario utilizzare qualcosa della famiglia select o poll, il che significa che si è costretti a utilizzare una pipe per avviare tutti gli eventi non relativi ai file.
Modifica :Linux ha eventfd e timerfd. Questi possono essere aggiunti al tuo epoll
list e utilizzato per uscire dal epoll_wait
rispettivamente quando viene attivato da un altro thread o su un evento timer.
C'è un'altra opzione e cioè i segnali. Si può usare fcntl
modificare il descrittore di file in modo tale che venga emesso un segnale quando il descrittore di file diventa attivo. Il gestore del segnale può quindi inviare un messaggio pronto per il file su qualsiasi tipo di coda di tua scelta. Può trattarsi di un semplice semaforo o di una coda guidata da mutex/condvar. Dal momento che ora non si usa più select
/poll
, non è più necessario utilizzare una pipe per mettere in coda messaggi non basati su file.
Avviso sulla salute:non l'ho provato e anche se non riesco a capire perché non funzionerà, non conosco davvero le implicazioni sulle prestazioni del signal
approccio.
Modifica:manipolare un mutex in un gestore di segnale è probabilmente una pessima idea.
Ho risolto questo problema esatto usando ciò che dici, pipe () e libevent (che avvolge epoll). Il thread di lavoro scrive un byte nella sua pipe FD quando la sua coda di output passa da vuota a non vuota. Ciò riattiva il thread IO principale, che può quindi acquisire l'output del thread di lavoro. Funziona alla grande ed è in realtà molto semplice da codificare.
Hai il tag Linux, quindi lo eliminerò:le code di messaggi POSIX fanno tutto questo, il che dovrebbe soddisfare la tua richiesta "incorporata" se non il tuo desiderio multipiattaforma meno desiderato.
La sincronizzazione thread-safe è integrata. Puoi bloccare i tuoi thread di lavoro alla lettura della coda. In alternativa, MQ può utilizzare mq_notify() per generare un nuovo thread (o segnalarne uno esistente) quando viene inserito un nuovo elemento in coda. E dato che sembra che userai select(), l'identificatore di MQ (mqd_t) può essere usato come descrittore di file con select.