Use std::lock_guard with try_lock
Asked Answered
D

2

46

Is there a way I can tell std::lock_guard to call try_lock instead of lock when it acquires the mutex?

The only way I could think of is to use std::adopt_lock:

if (!_mutex.try_lock())
{
    // Handle failure and return from the function
}
std::lock_guard<my_mutex_class> lock(_mutex, std::adopt_lock);

Is there a built-in solution for my problem rather then acquiring the lock explicitly and then give lock_guard the responsibility for releasing it?

Dumps answered 29/11, 2015 at 8:31 Comment(0)
Y
85

A basic design invariant of lock_guard is that it always holds the lock. This minimizes the overhead since its destructor can unconditionally call unlock(), and it doesn't have to store extra state.

If you need the try-to-lock behavior, use unique_lock:

std::unique_lock<std::mutex> lock(_mutex, std::try_to_lock);
if(!lock.owns_lock()){
    // mutex wasn't locked. Handle it.
}
Yeld answered 29/11, 2015 at 9:49 Comment(6)
You can use std::lock_guard as follows: if (_mutex.try_lock()) { std::lock_guard<std::mutex> lock(_mutex, std::adopt_lock); } (from stackoverflow.com/a/30457040)Multure
@Multure you mean, exactly what the question is trying to avoid?Yeld
Yes, yes exactly. I should read the questions as well, not just the answers... facepalmMulture
I personally perfer if(auto lock = std::unique_lock{_mutex, std::try_to_lock) { do_stuff(); }Flocky
@BennoStraub the code you posted does not work, it should be: std::unique_lock<std::mutex> lock(g_i_mutex, std::try_to_lock); if (lock.owns_lock()) {}Tm
@VincentRicosti It definitively works in C++11 and up. It inverts the logic though. You may also have to replace std::unique_lock{ ... } with std::unique_lock<std::mutex>(...) in older C++ versions, because template parameter deduction and the curly brace stuff isn't available.Flocky
T
0

This method can be used to execute only if try_lock succeeds:

{
    std::mutex mutex;
    tryLockAndExecute(mutex,[this]()
    {
        // your code here
    });
}

Implementation:

void tryLockAndExecute(std::mutex& mutex, std::function<void()> execute)
{
    std::exception_ptr exceptionPtr;
    if (mutex.try_lock())
    {
        try
        {
            execute();
        }
        catch (...)
        {
            exceptionPtr = std::current_exception();
        }
        mutex.unlock();
        if (exceptionPtr)
        {
            std::rethrow_exception(exceptionPtr);
        }
    }
}
Tinfoil answered 28/9, 2023 at 13:35 Comment(1)
Is there any reason to prefer this to unique_lock?Pardoes

© 2022 - 2024 — McMap. All rights reserved.