No, you most likely see that th1 always starts first, because building the stream for this variable first (and building the stream is expensive), so th2 starts after. This does not mean that there is order.
The join() call has nothing to do with which thread starts first, which is executed when building, when you provide the called one.
th1 can be constructed and then stopped by the OS, which will then start th2 . There is no order if you do not implement it.
Consider this example, which gives a much fairer start to both threads, sometimes it displays thread 1 as the first to get a lock, sometimes it gives thread 2.
Example:
#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; }
source share