Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Recursive mutex and QWaitCondition
QtWS25 Last Chance

Recursive mutex and QWaitCondition

Scheduled Pinned Locked Moved General and Desktop
5 Posts 2 Posters 5.4k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    samapico
    wrote on last edited by
    #1

    I know these two things don't quite work together, but I kind of need them both for something... There's probably a way to work around it, but I'm pretty new with all things Qt so I thought you guys might be able to help me out.

    I won't exactly show real code, but imagine all these methods are public in a class, and multiple threads can work on the same object.
    If I understand how recursive mutexes work, you'd need one in that kind of situation below, right?
    @class myclass
    {
    QMutex mutex;

    funcA()
    {
    mutex.lock();

    //... do stuff

    mutex.unlock();
    }

    funcB()
    {
    mutex.lock();

    //... do some stuff
    funcA();
    //... do some more stuff

    mutex.unlock();
    }

    } //myclass@

    My class has this kind of stuff, so I need a recursive mutex. Otherwise, I'll get deadlocks, or the mutex will unlocked way too early, causing potential unexpected behavior.

    Now, in one of the methods, I want to be able to pause the thread and wait for another method to be called by another thread. Something like this:

    @class myclass
    {
    QMutex mutex;
    QQueue<QWaitCondition*> queue; //some kind of waiting queue

    funcA2()
    {
    mutex.lock();

    //... do stuff

    mutex.unlock();
    }

    funcB2()
    {
    mutex.lock();

    //... do some stuff

    //under some conditions, wait for funcC2 to be called by another thread
    if (...)
    {
    QWaitCondition cond;
    queue.append(&cond);

    cond.wait(&mutex, 10000); //if mutex is recursive, this will always fail

    if (queue.removeOne(&cond))
    {
    //timer expired, noone called funcC2
    }
    else
    {
    //another thread called funcC2, which removed &cond from the queue already
    }
    }

    //... do some stuff
    funcA2();
    //... do some more stuff

    mutex.unlock();
    }

    funcC2()
    {
    mutex.lock();

    if (!queue.isEmpty())
    queue.takeFirst()->wakeOne();

    mutex.unlock();
    }

    } //myclass@

    That's more or less what I have at the moment... but it just can't work:
    If my mutex is recursive, the QWaitCondition.wait(...) call returns immediatly. If my mutex is non-recursive, I get deadlocks, or I unlock my object too early.
    I can use another dummy mutex for the .wait call, and unlock / relock my mutex manually before and after it, but I lose the atomic transition...
    I could reorganize my code to only have a single pair of Lock/Unlock in each public method, and make sure none of the public methods are calling another, and make my mutex non-recursive, but this makes it very easy to introduce major bugs with minor code tweaks. Maybe that's the way to do it, I have no idea... I can't say I worked with mutexes that much, but I always tend to go with the "put the lock in every function that play with your data" kind of approach, and that includes private functions called by the (also lock'd) public ones...

    Maybe my design is severely flawed, or maybe I'm missing something obvious I could use. Either way, thanks in advance for any suggestions

    1 Reply Last reply
    0
    • G Offline
      G Offline
      giesbert
      wrote on last edited by
      #2

      The problem you describe is the defined behavior of "QWaitCondition::wait":http://doc.qt.nokia.com/latest/qwaitcondition.html#wait

      bq. Releases the locked mutex and waits on the wait condition. The mutex must be initially locked by the calling thread. If mutex is not in a locked state, this function returns immediately. If mutex is a recursive mutex, this function returns immediately. ...

      Nokia Certified Qt Specialist.
      Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

      1 Reply Last reply
      0
      • S Offline
        S Offline
        samapico
        wrote on last edited by
        #3

        I know... what I'm asking is: Because of this, how can I accomplish what I'm trying to do? As I said, it's probably more of a design issue and I guess I need to find a different way to signal the other thread. But I was wondering if you guys had an idea of something that could accomplish something similar to QWaitCondition, but that could work in this case, where I need a recursive mutex.

        1 Reply Last reply
        0
        • G Offline
          G Offline
          giesbert
          wrote on last edited by
          #4

          what you could do is have interface methods and internal methods. do the locking on the interface methods level and only call internals inside.

          @
          class myclass
          {
          public:
          funcA2()
          {
          mutex.lock();
          funA2int();
          mutex.unlock();
          }
          funcB2()
          {
          mutex.lock();
          funB2int();
          mutex.unlock();
          }
          funcC2()
          {
          mutex.lock();
          funC2int();
          mutex.unlock();
          }

          private:
          funA2int()
          {
          //... do stuff
          }

          funB2int()
          {
              //... do some stuff
              //under some conditions, wait for funcC2 to be called by another thread
              if (...)
              {
                  QWaitCondition cond;
                  queue.append(&cond);
                  cond.wait(&mutex, 10000); //if mutex is recursive, this will always fail
                  if (queue.removeOne(&cond))
                  {
                      //timer expired, noone called funcC2
                  }
                  else
                  {
                      //another thread called funcC2, which removed &cond from the queue already
                  }
              }
          
              //... do some stuff
              funcA2int();
              //... do some more stuff
          }
          
          QMutex mutex;
          QQueue<QWaitCondition*> queue; //some kind of waiting queue
          
          
          funcC2int()
          {
              if (!queue.isEmpty())
                  queue.takeFirst()->wakeOne();
          }
          

          } //myclass
          @

          Nokia Certified Qt Specialist.
          Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

          1 Reply Last reply
          0
          • S Offline
            S Offline
            samapico
            wrote on last edited by
            #5

            That would work, I guess... It can get pretty messy though.

            But I think I can make it work using a second non-recursive mutex that is only used to inter-lock my two methods, while the "global" recursive one can still be used everywhere safely... as long as one specific method (illustrated by funcB2 in the example) is not called by another locked method, which should work in my case.

            Thanks again; I just wanted to be sure I wasn't missing an obvious solution or something.

            1 Reply Last reply
            0

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved