Waiting for the first unlocked QMutex if there are few QMutex

734 views Asked by At

I have two QMutex objects and I need to lock them both, erase() method. But the sequence is not important.
So, now I am waiting while one QMutex is in unlocked (QMutexLocker locker(&listMutex)) state and than I wait for another (QMutexLocker locker(&writeMutex)).
But it would be more efficiently to wait for a mutex which is unlocked the first. And than wait for the other one. Than waiting time will be shorter.
How could be implemented such behaviour?
Should I create additional recursive QMutex or QSemaphore and synchronize states of both QMutex with this new object and than wait not for my QMutex but for this new object.
That should work, but maybe there is an easier way without duplicating QMutex objects?

class MyQThread:
     public: QThread
{
    ...
    QList<QString> list;
    QString string;
    QMutex listMutex;
    QMutex writeMutex;
}

void MyQThread::erase()
{
     QMutexLocker locker(&listMutex);
     list.clear();
     QMutexLocker locker(&writeMutex);
     string.clear();
}  

void MyQThread::run()
{
     forever
     {
         listMutex.lock();             
         string = list.takeFirst();
         listMutex.unlock();

         writeMutex.lock();
         if(!string.isEmpty())
             ...//do something
         writeMutex.unlock();
     }
}  
2

There are 2 answers

6
code_fodder On

ah, ok...

Its a bit of a fiddle, but you can use "tryLock()", somthing like this:

// You could add a loop around this until both are done...

if (listMutex.tryLock())
{
    // list locked... do list stuff
    listMutex.unlock();
}
else if (writeMutex.tryLock())
{
    // writelocked... do writestuff
    listMutex.unlock();
}

Note: tryLock will return true if it acutally locked the mutex, or false if it did not.

---- EDIT Example 2: ----

// Againm, you can stick a loop around this until you are done...

if (listMutex.tryLock())
{
    // list locked... do list only stuff
}

if (writeMutex.tryLock())
{
    // writelocked... do write only stuff
}

if (listMutex.tryLock() && writeMutex.tryLock())
{
    // Both locked... do write and list stuff
}

// Make sure both are unlocked at the end
listMutex.unlock();
listMutex.unlock();
0
Bastian On

You could do the locking in parallel threads. Please try the following example (I didn't test it):

class BackgroundLocker : protected QThread {
    protected:
        QMutex& mutex;
        void run() {
            mutex.lock();
        }
    public:
        BackgroundLocker(QMutex& mutex): mutex(mutex) {
            start();
        }
        ~BackgroundLocker(QMutex& mutex) {
            mutex.unlock();
        }
        void waitLock() {
            QThread::wait();
        }
};

void MyQThread::erase() {
    BackgroundLocker locker1(listMutex);
    BackgroundLocker locker2(writeMutex);
    locker1.waitLock();
    locker2.waitLock();
    list.clear();
    string.clear();
}