doubts in the behaviour of thread::join()

I am trying to understand what thread::join() actually does. From here I found the definition I describe below:
https://stackoverflow.com/questions/15148057/what-does-stdthread-join-do

join() suspends the thread until another one finishes


This is the code where I am testing the join() function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>
#include <string>
#include <chrono>
#include <mutex>
#include <thread>

using namespace std;

//Prototypes
void ten_thread_fn();
void five_thread_fn();

int global_counter=0;
mutex counter_mutex;

int main()
{
    cout<<"Starting thread ten..."<<endl;
    thread ten_thread(ten_thread_fn);
    cout<<"Running ten thread"<<endl;

    thread five_thread(five_thread_fn);
    cout<<"Running five thread"<<endl;

    ten_thread.join(); 						//join() suspends the ten thread until another one finishes
    cout<<"Ten thread is done"<<endl;
    five_thread.join();						//join() suspends the five thread until another one finishes
    cout<<"Five thread is done"<<endl;
}

void ten_thread_fn(){
	cout<<"*****void ten_thread_fn() is executed"<<endl;
    for(int i=0; i<10; i++){
        counter_mutex.lock();				//"mutex" suspends the current thread until mutex owner releases it or locks right away if it isn't locked
        global_counter++;
        thread::id id= this_thread::get_id();
        cout<<"*****Iteration: "<<i;
        cout<<" Thread_id: "<<id<<endl;
        counter_mutex.unlock();
        cout<<"*****Updated from ten_thread"<<endl;
        this_thread::sleep_for(chrono::seconds(1));
    }
    //When this thread finishes we wait for it to join (so the join function will become true)
}

void five_thread_fn(){
	cout<<"*****void five_thread_fn() is executed"<<endl;
    for(int i=0; i<5; i++){
        counter_mutex.lock();				//"mutex" suspends the current thread until mutex owner releases it or locks right away if it isn't locked
        global_counter++;
        thread::id id= this_thread::get_id();
        cout<<"*****Iteration: "<<i;
        cout<<" Thread_id: "<<id<<endl;
        counter_mutex.unlock();
        cout<<"*****Updated from five_thread"<<endl;
        this_thread::sleep_for(chrono::seconds(1));
    }
}


This is the output of the execution:
>Starting thread ten...
>Running ten thread
>Running five thread
>*****void five_thread_fn() is executed
>*****Iteration: 0 Thread_id: 3065903936
>*****Updated from five_thread
>*****void ten_thread_fn() is executed
>*****Iteration: 0 Thread_id: 3074296640
>*****Updated from ten_thread
>*****Iteration: 1 Thread_id: 3065903936
>*****Updated from five_thread
>*****Iteration: 1 Thread_id: 3074296640
>*****Updated from ten_thread
>*****Iteration: 2 Thread_id: 3074296640
>*****Updated from ten_thread
>*****Iteration: 2 Thread_id: 3065903936
>*****Updated from five_thread
>*****Iteration: 3 Thread_id: 3074296640
>*****Updated from ten_thread
>*****Iteration: 3 Thread_id: 3065903936
>*****Updated from five_thread
>*****Iteration: 4 Thread_id: 3074296640
>*****Updated from ten_thread
>*****Iteration: 4 Thread_id: 3065903936
>*****Updated from five_thread
>*****Iteration: 5 Thread_id: 3074296640
>*****Updated from ten_thread
>*****Iteration: 6 Thread_id: 3074296640
>*****Updated from ten_thread
>*****Iteration: 7 Thread_id: 3074296640
>*****Updated from ten_thread
>*****Iteration: 8 Thread_id: 3074296640
>*****Updated from ten_thread
>*****Iteration: 9 Thread_id: 3074296640
>*****Updated from ten_thread
>Ten thread is done
>Five thread is done

According to the definition of join():
join() suspends the thread until another one finishes

or from cplusplus:
The function returns when the thread execution has completed.
This synchronizes the moment this function returns with the completion of all the operations in the thread: This blocks the execution of the thread that calls this function until the function called on construction returns (if it hasn't yet).


I was expecting one thread to finish the for loop execution before the other starts. However as seen in the output, the threads alternate. Why is that?
Last edited on
The thread starts executing as soon as the std::thread object is created and the system finishes initializing its internal state. The alternating behavior is a coincidence; the order of execution of separate threads is undefined, unless synchronization primitives are involved.

ten_thread.join(); //join() suspends the ten thread until another one finishes
You got it sort of backwards. What std::thread::join() does is cause the caller to wait until the corresponding thread finishes. In other words, in this line of code, main() will wait until ten_thread_fn() returns.
Thank you @helios.
Indeed, I commented ten_thread.join() and the main execution ended as soon as five_thread.join() finished. I mean without waiting for finishing the 10 iterations of the void ten_thread_fn() :).

Just need one clarification and have one doubt on your description:
1.- Clarification:
The thread starts executing as soon as the std::thread object is created

Do you mean here?
thread ten_thread(ten_thread_fn);

2.- Doubt:
system finishes initializing its internal state

What does the system need to initialize its internal state?

Last edited on
1. Yes.
2. That's up to the system. At a bare minimum the system will need to allocate a stack and some structures to support context switching and scheduling. If you want a more concrete answer you can take a look at the implementation of pthread_create() in the Linux or FreeBSD kernels.
take a look at the implementation of pthread_create() in the Linux or FreeBSD kernels

Thanks for the hint!
Last edited on
Topic archived. No new replies allowed.