Sono interessato alle prestazioni del mutex e del passaggio dei messaggi nell'ultimo gcc con i thread basati su pthread e un ambiente di sviluppo di Ubuntu. Un buon problema generico per questo sono i filosofi cenati in cui ogni filosofo usa la forchetta lh e rh condivisa con il vicino di sinistra e di destra. Aumento il numero di filosofi a 99 per mantenere occupato il mio processore quad core.Prestazioni dei thread in C++ 11
int result = try_lock(forks[lhf], forks[rhf]);
il codice di cui sopra permette al mio filosofo per tentare di afferrare le due forchette cui hanno bisogno per mangiare con.
// if the forks are locked then start eating
if (result == -1)
{
state[j] = philosophers::State::Eating;
eating[j]++;
if (longestWait < waiting[j])
{
longestWait = waiting[j];
}
waiting[j] = 0;
} else {
state[j] = philosophers::State::Thinking;
thinking[j]++;
waiting[j]++;
}
il codice sopra controlla i miei filosofi progredire mangiando o pensando a seconda se riescono a prenotare le due forchette.
{
testEnd te(eating[j]+thinking[j]-1);
unique_lock<mutex> lk(cycleDone);
endCycle.wait(lk, te);
}
il codice sopra attende tutti i filosofi per completare la selezione dopo questo tempo il filosofo è libero di effettuare un nuovo tentativo:
if (philosophers::State::Eating == state[j])
{
state[j] = philosophers::State::Thinking;
forks[lhf].unlock();
forks[rhf].unlock();
}
Ho un filo conduttore che controlla filosofi e mosse li da un ciclo all'altro che consente loro circa 10 secondi di mangiare e pensare il più possibile. Il risultato è di circa 9540 cicli con alcuni filosofi affamati e altri che hanno molto da mangiare e molto tempo per pensare! Così ho bisogno di proteggere i miei filosofi di fame e di aspettare troppo a lungo in modo da aggiungere più logica per evitare un eccesso di mangiare richiedendo filosofi mangiare per rilasciare e pensare piuttosto che gab le stesse forchette, dopo una piccola pausa:
// protect the philosopher against starvation
if (State::Thinking == previous)
{
result = try_lock(forks[lhf], forks[rhf]);
}
Ora ho 9598 cicli con ogni filosofo che ottiene una quota relativamente uguale di mangiare (2620 - 2681) e penso con l'attesa più lunga di 14. Non male. Ma non sono soddisfatto, quindi ora mi sbarazzerò di tutti i mutex e delle serrature e lo terrò semplice con gli stessi filosofi che mangiano in cicli regolari e gli strani filosofi che mangiano in cicli dispari. Io uso un metodo semplice di sincronizzazione filosofi
while (counter < counters[j])
{
this_thread::yield();
}
impedisce a un filosofo di mangiare o pensare troppe volte utilizzando un contatore ciclo mondiale. Lo stesso periodo di tempo ei filosofi gestiscono circa 73543 cicli con 36400 pasti e non più di 3 cicli di attesa. Quindi il mio semplice algoritmo senza lock è sia più veloce che ha una migliore distribuzione dell'elaborazione tra i vari thread.
Qualcuno può pensare a un modo migliore per risolvere questo problema? Temo che quando implemento un sistema complesso con più thread, se seguo le tecniche di mutex e di trasmissione dei messaggi tradizionali, finirò con l'elaborazione più lenta del necessario e possibile sbilanciata sui vari thread nel mio sistema.
Una pianificazione sincronizzata selezionata per essere ottimale batte uno generato a caso. Grande. Dov'è il problema? –
La proposta 'std :: hemlock' per C++ 1y dovrebbe porre fine a questo problema una volta per tutte. –
Questo sembra non avere nulla a che fare con C++ 11 di per sé. –