Behind QMutex::lock() Function
-
Hi everyone
I thought a lot and i couldn't find a way that a function actually locking variables at some lines. So i wonder how it works actually. Is it really locking variables or there is some other method it is using. Can someone give me a little detail about how it works.
Thanks in advance
-
My guess is that it is saying other threads "wait, i am doing something important, dont do anything".
-
The topic is vast, so to fit it in a forum post and not explode your head I'll be brief and make shortcuts (both mental and technical).
In the simplest form a mutex is some primitive (like an int) that indicates if it is locked or not (e.g. 0 means unlocked, non-0 means locked).
A simple lock implementation would be a thread writing 1 to that variable. It can only do so if the value is not already 1, at which point it can either wait for it to become 0 or bail, which would correspond to lock() and trylock() functions. The thread that has written 1 to the variable (locked it) is the only one that can unlock it.So in pseudocode (really! don't try to implement it like that) this would look something like this:
void Thread::lock(int& mutex) { while(mutex != 0); //wait mutex = 1; this->ImTheOnethatLocked = true; } bool Thread::trylock(int& mutex) { if(mutex == 0) { mutex = 1; this->ImTheOnethatLocked = true; return true; } else return false; } void Thread::unlock(int& mutex) { if(this->ImTheOnethatLocked) { mutex = 0; this->ImTheOnethatLocked = false; } }
That's all fine and all but what if two threads try to lock it at the same time i.e. they both test
if(mutex == 0)
and deduce they can lock it? That's the actual trick. For this to work the operation of test and set (if
and=
) need to be atomic (done uninterrupted in a single go). This is called an "acquire semantic" and to be implemented correctly requires hardware support (there's a CPU instruction that does that).
Up until c++11 it was not exposed directly in the language so there was no standard compliant way to write a mutex in c++. All implementations (including Qt) did it (and many do still) using OS provided facilities (implemented in assembly, intrinsics or other low level way). In c++11 the standard (finally!) recognized an existance of threads and gave us access to such low level facilities via stuff like the std::atomic and std::thread that allow to implement a mutex in a standard compliant c++ only (which stl does).If you're interested in the nitty gritty details some google keywords would be "acquire and release semantics", "atomics" and "memory barrier". My advice - get at it when you're fresh and after a good night's sleep because it makes most people head hurt ;)
One talk available online I can recommend is the atomic<> Weapons part 1 & 2 given by Herb Sutter a few years back. Great (but hard!) stuff. -
"Make everything as simple as possible, but not simpler" - Einstein
I really like how simple and to the point your answer is. I am going to learn about it when i have time.
Thanks a lot.