I've reached a point in my project that requires communication between threads on resources that very well may be written to, so synchronization is a must. However I don't really understand synchronization at anything other than the basic level.
Consider the last example in this link: http://www.bogotobogo.com/cplusplus/C11/7_C11_Thread_Sharing_Memory.php
#include <iostream> #include <thread> #include <list> #include <algorithm> #include <mutex> using namespace std; // a global variable std::list<int>myList; // a global instance of std::mutex to protect global variable std::mutex myMutex; void addToList(int max, int interval) { // the access to this function is mutually exclusive std::lock_guard<std::mutex> guard(myMutex); for (int i = 0; i < max; i++) { if( (i % interval) == 0) myList.push_back(i); } } void printList() { // the access to this function is mutually exclusive std::lock_guard<std::mutex> guard(myMutex); for (auto itr = myList.begin(), end_itr = myList.end(); itr != end_itr; ++itr ) { cout << *itr << ","; } } int main() { int max = 100; std::thread t1(addToList, max, 1); std::thread t2(addToList, max, 10); std::thread t3(printList); t1.join(); t2.join(); t3.join(); return 0; }
The example demonstrates how three threads, two writers and one reader, accesses a common resource(list).
Two global functions are used: one which is used by the two writer threads, and one being used by the reader thread. Both functions use a lock_guard to lock down the same resource, the list.
Now here is what I just can't wrap my head around: The reader uses a lock in a different scope than the two writer threads, yet still locks down the same resource. How can this work? My limited understanding of mutexes lends itself well to the writer function, there you got two threads using the exact same function. I can understand that, a check is made right as you are about to enter the protected area, and if someone else is already inside, you wait.
But when the scope is different? This would indicate that there is some sort of mechanism more powerful than the process itself, some sort of runtime environment blocking execution of the "late" thread. But I thought there were no such things in c++. So I am at a loss.
What exactly goes on under the hood here?
The point of lock_guard is just to make locking and unlocking the mutex easier for you. For example, if you manually lock / unlock , but your function throws an exception somewhere in the middle, it will never reach the unlock statement.
std::lock_guard The class lock_guard is a mutex wrapper that provides a convenient RAII-style mechanism for owning a mutex for the duration of a scoped block. When a lock_guard object is created, it attempts to take ownership of the mutex it is given.
A lock_guard always holds a lock from its construction to its destruction. A unique_lock can be created without immediately locking, can unlock at any point in its existence, and can transfer ownership of the lock from one instance to another.
The benefit to using std::unique_lock<> comes from two things: you can transfer ownership of the lock between instances, and. the std::unique_lock<> object does not have to own the lock on the mutex it is associated with.
Let’s have a look at the relevant line:
std::lock_guard<std::mutex> guard(myMutex);
Notice that the lock_guard
references the global mutex myMutex
. That is, the same mutex for all three threads. What lock_guard
does is essentially this:
myMutex
and keeps a reference to it.myMutex
.The mutex is always the same one, it has nothing to do with the scope. The point of lock_guard
is just to make locking and unlocking the mutex easier for you. For example, if you manually lock
/unlock
, but your function throws an exception somewhere in the middle, it will never reach the unlock
statement. So, doing it the manual way you have to make sure that the mutex is always unlocked. On the other hand, the lock_guard
object gets destroyed automatically whenever the function is exited – regardless how it is exited.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With