I am a chip designer and we use mutex in our circuits all the time for atomic memory accesses. I am learning to code in CPP and I am having hard time understanding how the Mutex works in CPP.
I understand that any program is a process and threads under a process have their own local objects, in addition to global objects that are accessible from any thread under this process.
In my attempt to understand mutex more intimately, I found this example at http://www.cplusplus.com/reference/condition_variable/condition_variable/
1 // condition_variable example
2 #include <iostream> // std::cout
3 #include <thread> // std::thread
4 #include <mutex> // std::mutex, std::unique_lock
5 #include <condition_variable> // std::condition_variable
6
7 std::mutex mtx;
8 std::condition_variable cv;
9 bool ready = false;
10
11 void print_id (int id) {
12 std::unique_lock<std::mutex> lck(mtx);
13 while (!ready) cv.wait(lck);
14 // ...
15 std::cout << "thread " << id << '\n';
16 }
17
18 void go() {
19 std::unique_lock<std::mutex> lck(mtx);
20 ready = true;
21 cv.notify_all();
22 }
23
24 int main ()
25 {
26 std::thread threads[10];
27 // spawn 10 threads:
28 for (int i=0; i<10; ++i)
29 threads[i] = std::thread(print_id,i);
30
31 std::cout << "10 threads ready to race...\n";
32 go(); // go!
33
34 for (auto& th : threads) th.join();
35
36 return 0;
37 }
Possible output (thread order may vary):
10 threads ready to race...
thread 2
thread 0
thread 9
thread 4
thread 6
thread 8
thread 7
thread 5
thread 3
thread 1
In line 28 and 29, 10 threads are scheduled. All of them are trying to lock same mutex (mtx). As I understand, one of the 10 thread will get the lock and will wait at line 13, while other 9 threads will try to get the lock and get blocked at line 12 itself.
Then comes the call to function go() at line 32. Go() also is trying to get the lock for the same mutex at line 19. But it should not get it as one print_id() thread is owning the lock. As per my understanding, this should result in a deadlock as go() is blocked at line 19, and can't get past that line, and consequently, can't send the cv.notify_all();
But the result in the link claims otherwise. It shows that go() effortlessly acquired the lock and sent the notify that in turn started the domino effect on 10 threads.
What am I missing? Is there some specific rule embedded in CPP specification that is allowing go() function to acquire the lock from the thread that was owning it? I have spent many hours in net searching for an answer, but in vain.
I will really appreciate some explanation of this phenomenon.