2013-06-09 13 views
8

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.

+3

Una pianificazione sincronizzata selezionata per essere ottimale batte uno generato a caso. Grande. Dov'è il problema? –

+1

La proposta 'std :: hemlock' per C++ 1y dovrebbe porre fine a questo problema una volta per tutte. –

+0

Questo sembra non avere nulla a che fare con C++ 11 di per sé. –

risposta

2

Questo è un modo interessante per esplorare i problemi del threading in C++.

Per affrontare punti specifici:

temo che quando implemento un sistema complesso con più thread che se seguo tecniche tradizionali mutex e segnalazione passando io finire con più lento di elaborazione sbilanciato necessario e possibile in i vari thread nel mio sistema.

Sfortunatamente, la risposta migliore che posso darvi è che questa è una paura ben fondata.Il costo della pianificazione e della sincronizzazione è molto specifico per l'applicazione, tuttavia diventa una decisione ingegneristica quando si progetta un sistema di grandi dimensioni. Innanzitutto, la programmazione è NP-Hard (http://en.wikipedia.org/wiki/Multiprocessor_scheduling) ma ha buone approssimazioni.

Per quanto riguarda il vostro esempio particolare, penso che sia difficile trarre conclusioni generali basate sui risultati che avete presentato - c'è un punto di partenza principale: il compromesso tra sincronizzazione a grana grossa e sincronizzazione a grana fine. Questo è un problema ben studiato e alcune ricerche potrebbero essere utili (ad es. http://ieeexplore.ieee.org/xpls/abs_all.jsp?arnumber=744377&tag=1).

Nel complesso, questo tocca un problema di progettazione che sarà specifico per il problema che si desidera risolvere, il sistema operativo e l'hardware.

Problemi correlati