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.
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.
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With