2015-10-04 87 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