考虑这个简单的并发示例:
#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
将先执行然后再执行th2
?
答案 0 :(得分:6)
不,你最有可能看到th1
总是首先开始,因为该变量的线程构造首先完成(并且线程构造很昂贵),因此th2
开始。这并不意味着有订单。
调用join()
与首先执行哪个线程没有任何关系,这是在你提供可调用时在构造时完成的。
th1
然后由OS停止,这将导致th2
首先运行。除非你实施一个订单,否则没有订单。
考虑这个例子,它给两个线程提供了更公平的启动,它有时输出线程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;
}