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".


  • Moderators

    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.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.