2015-10-04 88 views
5

線程考慮一個簡單的例子同意:訂單在執行

#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; 
} 

是否總是保證th1將執行for循環的第一個線程?

意思是,當我這樣做:

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

那我可以絕對確保th1將先​​執行?

+1

當處理併發編程時,不要對執行順序做任何假設。相反,假設所有情況都是可能的。這使得你的代碼更加可靠,反而更簡單。 –

+0

[你正在使用'std :: mutex'錯誤](http://kayari.org/cxx/antipatterns.html#locking-mutex),你不應該調用'std :: mutex :: lock()'和'的std ::互斥::解鎖()'。相反,在'print_block()'開始時創建'std :: lock_guard '並讓它爲你鎖定和解鎖互斥鎖。 –

回答

6

不,你最有可能看到th1總是首先啓動,因爲首先完成該變量的線程構造(並且線程構造是昂貴的),因此​​在之後開始。這並不意味着有訂單。

調用join()與首先執行哪個線程沒有任何關係,這是在構建時完成的,當您提供可調用的代碼時。

th1可以構建,然後由操作系統停滯,然後會導致​​首先運行。沒有訂單,除非你實施一個。

考慮下面這個例子,給出了一個更公平開始到兩個線程,它有時輸出線程1爲第一獲取鎖,它有時輸出線2

實施例:

#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

但在我的例子中,爲什麼訂單總是一樣的?先是'th1',然後是'th2'?即使我將這兩條線替換爲另一條線,順序也保持不變。只有當我更換建築時,訂單才改變。 – ron

+0

@ron當你互相替換了哪些線條?如果你指的是對'join()'的調用,那是因爲'join()'與線程開始執行的順序無關。我解釋了爲什麼首先構建一個線程通常會先於另一個線程啓動。 –

+0

好吧,讓我看看我是否得到了你:兩個線程都到達while循環('while(!go){}'),然後主線程在'go'標誌上翻轉,只有這樣,獲得鎖定? – ron