2015-10-04 15 views
5

Betrachten Sie diese einfache Zustimmung Beispiel:Reihenfolge der Themen in der Ausführung

#include <iostream>  // std::cout 
#include <thread>   // std::thread 
#include <mutex>   // std::mutex 

std::mutex mtx;   // mutex for critical section 

void print_block(int n, char c) { 
    // critical section (exclusive access to std::cout signaled by locking mtx): 
    mtx.lock(); 
    for (int i = 0; i<n; ++i) { std::cout << c; } 
    std::cout << '\n'; 
    mtx.unlock(); 
} 

int main() 
{ 
    std::thread th1(print_block, 50, '*'); 
    std::thread th2(print_block, 50, '$'); 

    th1.join(); 
    th2.join(); 

    return 0; 
} 

Ist es immer gewährleistet, dass th1 wird der erste Thread sein die for-Schleife auszuführen?

Bedeutung, wenn ich dies tun:

th1.join(); 
th2.join(); 

Dann kann ich absolut sicher sein, dass th1 zuerst ausgeführt wird und dann th2?

+1

Bei Behandeln Sie bei der gleichzeitigen Programmierung niemals eine Hypothese über die Reihenfolge der Ausführung. Gehen Sie im Gegenteil davon aus, dass alle Situationen möglich sind. Dies macht Ihren Code zuverlässiger und paradoxerweise einfacher. –

+0

[Sie verwenden 'std :: mutex 'falsch] (http://kayari.org/cxx/antipatterns.html#locking-mutex), sollten Sie niemals' std :: mutex :: lock() 'und 'std :: mutex :: unlock()'. Erstellen Sie stattdessen am Anfang von 'print_block()' 'std :: lock_guard ' und lassen Sie den Mutex für Sie sperren und entsperren. –

Antwort

6

Nein, Sie sehen am wahrscheinlichsten th1 immer zuerst starten, weil Thread-Konstruktion für diese Variable zuerst erfolgt (und Thread-Konstruktion ist teuer), damit th2 beginnt nach. Das bedeutet nicht, dass es eine Bestellung gibt.

Aufruf join() hat nichts damit zu tun, was Thread zuerst ausgeführt wird, das ist bei der Konstruktion getan, wenn Sie eine aufrufbar bereitstellen.

th1 kann durch das OS aufgebaut und dann angehalten werden, die dann th2 zuerst laufen verursachen würde. Es gibt keine Reihenfolge, außer Sie implementieren eine.

dieses Beispiel betrachten, die eine viel fairer Start in beiden Threads gibt, gibt sie manchmal Faden 1 als die erste ist, um die Sperre zu erwerben, es gibt manchmal Gewinde 2.

Beispiel:

#include <iostream>   // std::cout 
#include <string>   // std::string 
#include <unordered_map> // std::unordered_map<K, V> 
#include <thread>   // std::thread 
#include <mutex>   // std::mutex 
#include <atomic>   // std::atomic<T> 

std::unordered_map<std::thread::id, std::string> thread_map; 
std::mutex mtx;   // mutex for critical section 
std::atomic<bool> go{ false }; 

void print_block(int n, char c) 
{ 
    while (!go) {} // prevent threads from executing until go is set. 
    // critical section (exclusive access to std::cout signaled by locking mtx): 
    mtx.lock(); 

    std::cout << thread_map.find(std::this_thread::get_id())->second << 
     " acquires the lock.\n"; 

    mtx.unlock(); 
} 

int main() 
{ 
    std::thread th1(print_block, 50, '*'); 
    std::thread th2(print_block, 50, '$'); 

    thread_map.emplace(std::make_pair(th1.get_id(), "Thread 1")); 
    thread_map.emplace(std::make_pair(th2.get_id(), "Thread 2")); 

    go.store(true); 

    th1.join(); 
    th2.join(); 

    return 0; 
} 
+0

Aber in meinem Beispiel, warum ist die Reihenfolge immer gleich? zuerst 'th1' und dann' th2'? Selbst wenn ich die Linien durch die anderen ersetzte, blieb die Reihenfolge gleich. Erst als ich die Konstruktion ersetzte, änderte sich die Reihenfolge. – ron

+0

@ron Wenn Sie die Zeilen mit einander ersetzt haben? Wenn Sie die Aufrufe von 'join()' meinen, liegt das daran, dass 'join()' nichts mit der Reihenfolge zu tun hat, in der Threads mit der Ausführung beginnen. Ich erklärte, warum der Aufbau eines Threads in der Regel dazu führt, dass er vor dem anderen beginnt. –

+0

OK, lassen Sie mich sehen, wenn ich Sie bekam: beide Threads erreichen die While-Schleife ('while (! Go) {}') und dann dreht der Haupt-Thread auf die 'go'-Flag, und nur dann gibt es eine Race-Bedingung zu das Schloss erwerben? – ron

Verwandte Themen