Se una coda senza lock utilizza una variabile di condizione?

2

Supponiamo di avere una coda senza blocco in un'impostazione multithread. Fornisco già un metodo try_dequeue() che consente un errore facoltativo (comunicato tramite il tipo restituito) se la coda è vuota.

Ho trovato comodo disporre di un metodo T dequeue() sempre riuscito che non verrà restituito mentre la coda è vuota. Come consumatore, non mi interessa davvero quando ottengo il mio prodotto, voglio solo sapere non appena uno è disponibile.

La mia implementazione di dequeue() è piuttosto semplice:

while (true) {
    if (try_dequeue succeeded) return result;
    std::unique_lock<std::mutex> lk(mtx_);
    cond_.wait(lk, [this]{ return !empty(); });
}

Dove cond_ è segnalato da enqueuers e mtx_ guards cond_ .

La serializzazione in eccesso e la contesa tra i dequeuer causati da lk sembrano rallentare le cose. empty() sicuramente non ha bisogno di nulla da bloccare.

In ogni caso, cond_ sembra fuori luogo qui? L'unica ragione per cui esita a rimuoverlo è il caso in cui è presente un dequeuer (o più dequeuers) che attendono l'arrivo di un nuovo oggetto e ruotano pigramente sulla CPU senza alcuna indicazione che il thread di enqueuing abbia priorità.

Sembrerebbe che forse this_thread::yield() sia più appropriato qui, ma lo standard garantisce solo che il metodo sia un suggerimento, quindi c'è una possibilità di morire di fame qui.

Sembra che boost :: lockfree :: queue non fornisce affatto un metodo dequeue -like. Speriamo che l'opzione nucleare sia evitabile.

Come sottolinea l'utente, potremmo considerare una soluzione a questo problema come un approccio "ibrido" o "semi-bloccante" perché sarebbe auspicabile avere blocchi di dequeuers su code vuote, ma sarebbe anche bello per gli enqueuers non dover fare contemporaneamente un cambio di contesto completo al kernel.

Nota: Sì, tecnicamente l'inclusione di mtx_ nella coda rimuove l'attributo lockfree, ma penso che questa sia comunque una caratterizzazione accurata poiché dequeue() è l'unico metodo che usa mtx_ (segnale degli enqueuers senza blocco).

    
posta VF1 25.01.2015 - 02:10
fonte

1 risposta

1

Puoi usare try_lock per segnalare il cond_ durante l'accodamento. Questo avrà una condizione di competizione che può essere aggirata rendendo il tempo di attesa.

L'idea è che se il try_lock fallisce, allora un altro enqueuer sta anche cercando di svegliare i dequeuers, così potremmo anche lasciargli fare il lavoro o il dequeuer sta cercando di aspettare e lui può o non può avere ancora controllare la condizione . Se non ha poi bene, vedrà che la coda non è vuota e rilascia e riprova, se ha controllato, controllerà di nuovo dopo che scade il timeout.

    
risposta data 25.01.2015 - 03:04
fonte

Leggi altre domande sui tag