43

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?

Barry
  • 286,269
  • 29
  • 621
  • 977
Mr. Anderson
  • 1,609
  • 1
  • 13
  • 24

1 Answers1

80

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.
}
T.C.
  • 133,968
  • 17
  • 288
  • 421
  • 1
    You can use std::lock_guard as follows: `if (_mutex.try_lock()) { std::lock_guard lock(_mutex, std::adopt_lock); } ` (from https://stackoverflow.com/a/30457040) – iliis Jul 28 '20 at 13:47
  • 3
    @iliis you mean, exactly what the question is trying to avoid? – T.C. Jul 28 '20 at 13:48
  • 1
    Yes, yes exactly. I should read the questions as well, not just the answers... *facepalm* – iliis Aug 04 '20 at 14:24
  • 2
    I personally perfer `if(auto lock = std::unique_lock{_mutex, std::try_to_lock) { do_stuff(); }` – Benno Straub Oct 10 '20 at 07:55
  • 1
    @BennoStraub the code you posted does not work, it should be: std::unique_lock lock(g_i_mutex, std::try_to_lock); if (lock.owns_lock()) {} – Vincent Ricosti Aug 03 '21 at 16:36
  • @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(...)` in older C++ versions, because template parameter deduction and the curly brace stuff isn't available. – Benno Straub Aug 06 '21 at 19:44