Sto facendo una coda MPMC in C ++ e vorrei scoprire quale sarebbe la migliore interfaccia per un metodo try_dequeue
(sono not preoccupato per la sua implementazione). Mi piacerebbe fornire un metodo che non blocchi se la coda è vuota (come fa il mio metodo dequeue()
), ma in qualche modo notifica questo al chiamante.
Anche se fornisco un metodo bool empty() const
, questo purtroppo non va bene perché per una coda multithreading fare qualcosa sulla falsariga di if(!queue.empty()) queue.dequeue();
non fornisce garanzie.
Quello che attualmente ho è T try_dequeue()
, che genera un'eccezione se la coda è vuota. Questo sembra offrire l'interfaccia più intuitiva, ma una coda vuota non è certo una situazione eccezionale, e sembra un po 'strano usare le eccezioni per il controllo del flusso.
Un'altra opzione sarebbe bool try_dequeue(T* t)
, che scriverebbe a t
solo se la coda non era vuota e restituisce se è stato scritto t
. Dopo aver usato il metodo di eccezione sopra, questo sembra probabilmente meno intrusivo, ma richiederebbe che T
sia costruttivamente predefinito (o in qualche modo banalmente costruibile, quindi il chiamante può fare T t; queue.try_dequeue(&t);
) e assegnabile.
Non vorrei forzare quei requisiti su T
, quindi forse un approccio di tipo Java come optional<T> try_dequeue()
è in ordine. Uno dei problemi minori con questo è che dovrei implementare il mio (non posso usare boost). Forse, ancora più importante, rende l'interfaccia gonfia, nel senso che ora sto trascinando un altro tipo in cui sarebbe (si spera) evitabile, e, proprio come la situazione con% co_de di STL, ci impone di copiare una coppia , quindi "spiega" i suoi argomenti, costringe l'utente a un lungo e rituale rituale che deve essere ripetuto ogni volta che usa la funzione.
Forse mi preoccupo troppo dell'usabilità di set::insert
, dato che non ha nessuno dei problemi più seri che gli altri due approcci fanno, ma mi chiedo, quale sarebbe l'approccio migliore Qui? È il optional<T>
uno?
Modifica : mi è sembrato che ci sia anche un po 'di un'opzione di% co_de outlandish che sembra davvero carina (infatti questa avrà in realtà l'interfaccia più minimale che puoi avere, dove non c'è bisogno di alcuna logica esterna che imposti un optional
locale sul valore restituito). Purtroppo preferirei evitare l'overhead dovuto chiamando un bool try_dequeue(std::function<void(T&)>)
effettivo, e l'uso di una funzione template T
non è un'opzione, poiché si tratta di una classe derivata (da un'interfaccia generica std::function
).