2014-12-03 21 views
7

Quando faccio funzionare questo codice:Perché questi thread non vengono eseguiti in ordine?

#include <iostream> 
#include <thread> 
#include <mutex> 

std::mutex m; 

int main() 
{ 
    std::vector<std::thread> workers; 
    for (int i = 0; i < 10; ++i) 
    { 
     workers.emplace_back([i] 
     { 
      std::lock_guard<std::mutex> lock(m); 
      std::cout << "Hi from thread " << i << std::endl; 
     }); 
    } 

    std::for_each(workers.begin(), workers.end(), [] (std::thread& t) 
    { t.join(); }); 
} 

ho la output:

Hi from thread 7 
Hi from thread 1 
Hi from thread 4 
Hi from thread 6 
Hi from thread 0 
Hi from thread 5 
Hi from thread 2 
Hi from thread 3 
Hi from thread 9 
Hi from thread 8 

Anche se ho usato un mutex per mantenere un solo accesso thread alla volta. Perché l'output non è in ordine?

+0

un accesso thread alla volta hanno nulla a che fare con iniziare ordine –

+2

Mutex previene due di loro esecuzione quel pezzo di codice contemporaneamente. Ma perché ti aspetti qualche ordine particolare? –

+1

"Solo un accesso thread alla volta" è esattamente ciò che hai ottenuto. Ma perché ti aspettavi che succedesse in un ordine specifico? – AnT

risposta

19

Ciò che il tuo mutex ottiene è che non vengono stampati due thread contemporaneamente. Tuttavia, stanno ancora gareggiando per quale thread acquisisce prima il mutex.

Se si desidera eseguire l'esecuzione seriale, è sufficiente evitare i thread.

6

È totalmente a carico del sistema operativo in cui sono pianificati i thread degli ordini. Non puoi fare affidamento su nessun ordine. Supponiamo che sia totalmente casuale.

3

Si sta passando un lambda a emplace_back che viene utilizzato come parametro per il costruttore std :: thread. Vedere i dettagli per emplace_back copy/incollato di seguito da cppreference.com.

"Aggiunge un nuovo elemento alla fine del contenitore L'elemento viene costruito tramite std :: allocator_traits :: construct, che in genere utilizza il posizionamento-nuovo per costruire l'elemento sul posto nella posizione fornita dal contenitore. gli argomenti argomenti ... vengono inoltrate al costruttore come std :: forward (args) ...."

http://en.cppreference.com/w/cpp/container/vector/emplace_back

il mutex nel corpo del lambda non ha alcun effetto fino a quando lo std :: filo l'oggetto è stato completamente costruito e sta eseguendo il punto di ingresso del filo definito dal corpo lambda. Alcuni std :: threads potrebbero iniziare a essere eseguiti durante il ciclo oppure i thread potrebbero non avviarsi fino a quando il ciclo non sarà completato. Non puoi capirlo in modo portatile.

Dopo che il ciclo fora tutti i tuoi std :: threads nel tuo vettore, spetta al sistema operativo decidere in quale ordine i thread sono pianificati per l'esecuzione e questo è il modo in cui ottieni l'ordine casuale del tuo output.

2

L'ordine di esecuzione è irrilevante, non è possibile prevederlo e cambierà da esecuzione a corsa e nel tempo in una determinata esecuzione.

I progetti non devono mai dipendere dall'ordine di esecuzione dei thread in alcun modo o forma.

Va oltre: se N thread sono in attesa su un oggetto di sincronizzazione, ad esempio un mutex, e il mutex viene rilasciato, non c'è modo di prevedere in modo attendibile e portabile quale dei thread in attesa si risveglierà e afferrerà il mutex in seguito, indipendentemente dalle loro priorità di pianificazione relative.

non determinismo rende programmazione multithread difficile :-)

Problemi correlati