1

I've done a test but I don't figure out the order of execution of threads.

Here is my code:

void func1()
{
    std::this_thread::sleep_for(std::chrono::milliseconds(4000));
    std::cout<<"func1"<<std::endl;
}

void func2()
{
    std::this_thread::sleep_for(std::chrono::milliseconds(4000));
    std::cout<<"func2"<<std::endl;
}
int main()
{
    std::thread t(func1);
    std::thread t2(func2);

    t.join();
    t2.join();
    std::this_thread::sleep_for(std::chrono::milliseconds(8000));

    cout << "Hello World" << endl; 

    return 0;
}

In this case, I got the result below:
wait for 4 sec ---> "func1func2\n\n" is shown ---> wait for 8 sec ---> "Hello world" is shown.

If I change the order of the code in main as below:

t.join();
std::this_thread::sleep_for(std::chrono::milliseconds(8000));
t2.join();

I can get the same result just as above.

However, if I change it like this:

std::this_thread::sleep_for(std::chrono::milliseconds(8000));
t.join();
t2.join();

The result becomes:
wait for 4 sec ---> "func1func2\n\n" is shown ---> wait for 4 sec ---> "Hello world" is shown.
It seems that the main thread and t and t2 waits for 4 sec at the same time in this case.

How to explain all of these?

Yves
  • 11,597
  • 17
  • 83
  • 180
  • 1
    Running in parallel is exactly what threads are for. Only if you call `join` does one thread wait on the finished-state of the other. So in the last case, the threads wait for 4 seconds, finish, the main thread meanwhile waits for 8 seconds, then on `join` doesn't have to wait because both threads are finished, and outputs "Hello World". – Karsten Koop Jun 06 '16 at 14:08

1 Answers1

0

Without using locks (usually semaphores in your case) you just can't predict the order of execution of your thread. Only your process scheduler will determine this (very low level, which helps your processor to switch between contexts).

In your first case, the two thread start, and after 4sec print "funcX" (which corresponds to their functions). The main thread will wait the threads to join (purpose of join method) and then wait 8sec before printing the "hello world" : join method will block the execution of the main thread until threads are done.

In your second case, threads join AFTER the wait of 8sec : in fact the main thread and the two others wait in the same time. So after 4 second they print their message, and 4sec later (the main already waited 4sec) the "hello world" shows up !

Hope it will help you to understand what's going on here !

PaulDennetiere
  • 179
  • 2
  • 10
  • in fact there are 3 cases. Can you explain the second one? `t.join main.waitfor(8sec) t2.join`? I think your "second case" is my "third case". – Yves Jun 06 '16 at 14:16
  • The case given in your comment will execute like this : – PaulDennetiere Jun 06 '16 at 14:19
  • (mis use of my kb, sorry) What you seems to have difficulties to understand is the use of join() method : This method tells the main to wait for the thread to finish. However the thread can finish before that. – PaulDennetiere Jun 06 '16 at 14:29
  • For the first case, `join` blocked the main thread so after 4 sec of the two threads, the main thread should still wait for 8 sec. For the third case, the main thread and the two threads run together so they wait for 4 sec together. BUT for the second case, I can't understand: `t.join` blocked the main thread, right? why t and t2 can still execute together? In my opinion, it should be: wait for 4 sec ---> func1 is shown ---> wait for 4 sec ---> func2 is shown ----> wait for 4 sec -----> Hello World is shown. – Yves Jun 06 '16 at 14:46
  • 1
    Because join don't run your thread, but wait for it. The thread 2 will start at the exact moment of the execution of this line : std::thread t2(func2); If you want the result that you expected, try something like : thread t1, t1.join(), main.wait(), thread t2, t2.join() – PaulDennetiere Jun 06 '16 at 14:49
  • One solution (and the best solution) to have a full control of your thread is to use semaphores – PaulDennetiere Jun 06 '16 at 14:51
  • ah, I totally misunderstood join. Now I got it. Thanks. – Yves Jun 06 '16 at 14:52
  • Why would using semaphores be the best solution when C++11 doesn't provide it, but provides condition variables and promise/future? – stefaanv Jun 06 '16 at 15:07
  • My bad, I usually use C and not C++11, I wrongly assumed that C++ provides it. However you can still retrieve the semaphores behavior with conditions variables and promise/future. I'll edit my comment – PaulDennetiere Jun 07 '16 at 11:45
  • C posix threads library also don't provide semaphores. The only issue with condtion variables is that you should use it in a specific way [see link](http://stackoverflow.com/questions/5536759/condition-variable-why-calling-pthread-cond-signal-before-calling-pthread-co/5538447#5538447). When used this way, they provide the flexibility in describing how threads should be synchronized, better than semaphores can because these can only decide whether a counter is zero or not. So yes: a semaphore is a condition variable with a counter. – stefaanv Jun 07 '16 at 13:41
  • As a student, i had some courses on semaphores and the way to use it fro controlling process and thread in C, besides there is some documentation on the header file "semaphore.h" (POSIX) here : https://www.cs.cf.ac.uk/Dave/C/node26.html I'm still interested in learning new stuff, so can you explain to me what you meant by "C posix threads library also don't provide semaphores." ? – PaulDennetiere Jun 07 '16 at 14:19
  • @Pollux66: The link that you provided is about inter-process communication, for the threads API, see https://computing.llnl.gov/tutorials/pthreads/#PthreadsAPI , anyway, if you prefer using semaphores, that's fine by me, I just disagree that they are the best solution to work with threads. – stefaanv Jun 08 '16 at 07:25