Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using QMutex::tryLock and QMutexLocker

I have a background function that currently has something like follows:

void SomeClass::someFunction()
{
    if (!_mutex.tryLock())
    {
        // i want to know the mutex is locked, and then exit the function
        return;
    }
    else
    {
        _mutex.unlock();
    }

    QMutexLocker locker(_mutext);

    // do some stuff that **could** throw an exception
}

My dilemma concerns the _mutex.unlock() and QMutextLocker statement.

If the _mutex is locked, then I want to know about it. If it's not, then I want lock it. The problem is that I want to use QMutexLocker to lock _mutex for the bulk of the function. It's possible that the function could throw an exception, so manually unlocking _mutex could be difficult and error prone.

The above solution works but what concerns me is that sometime between the _mutex.unlock() and the deceleration of QMutexLocker something else could come along and lock the mutex.

Does anyone have any suggestions of a better way to do this?

Thank you.

like image 690
Addy Avatar asked Dec 03 '13 11:12

Addy


2 Answers

QMutexLocker clearly doesn't do quite what you need here, but you can write your own RAII wrapper easily enough:

class MutexTryLocker {
  QMutex &m_;
  bool locked_;
public:
  MutexTryLocker(QMutex &m) : m_(m), locked_(m.tryLock()) {}
  ~MutexTryLocker() { if (locked_) m_.unlock(); }
  bool isLocked() const { return locked_; }
}

and use it like so:

void SomeClass::someFunction() {
    MutexTryLocker locker(_mutex);

    if (!locker.isLocked()) {
        // we didn't get the lock, so return
        return;
    }

    // do some stuff that **could** throw an exception
}

Note this locker is just sample code: a production version should probably be explicitly noncopyable.


Historical note: JBL's comment referred to a paragraph addressing a sentence no longer in the question. I'll paraphrase it as:

... something else could come along and lock the mutex

If it's possible, it will happen. If it's unlikely, it will happen only after you deploy it/scale it up/sell it to a customer.

like image 67
Useless Avatar answered Oct 19 '22 09:10

Useless


I had a similar situation and ended up using the equivalent standard components instead of the Qt ones, as their lock_guard is able to handle an already locked mutex. If that is an option for someone, you could do it this way:

#include <mutex>

std::mutex _mutex;

void SomeClass::someFunction()
{
    if (!_mutex.try_lock())
    {
        // i want to know the mutex is locked, and then exit the function
        return;
    }

    // The lock_guard overtakes the already locked mutex
    const std::lock_guard<std::mutex> locker(_mutex, std::adopt_lock);

    // do some stuff that **could** throw an exception
}
like image 31
Adrian Schneider Avatar answered Oct 19 '22 07:10

Adrian Schneider