C++14 seems to have omitted a mechanism for checking whether an std::mutex is locked or not. See this SO question:

https://stackoverflow.com/questions/21892934/how-to-assert-if-a-stdmutex-is-locked

There are several ways around this, e.g. by using;

std::mutex::try_lock()
std::unique_lock::owns_lock()

But neither of these are particularly satisfying solutions.

try_lock() is permitted to return a false negative and has undefined behaviour if the current thread has locked the mutex. It also has side-effects. owns_lock() requires the construction of a unique_lock on top of the original std::mutex.

Obviously I could roll my own, but I'd rather understand the motivations for the current interface.

The ability to check the status of a mutex (e.g. std::mutex::is_locked()) does not seem like an esoteric request to me, so I suspect the Standard Committee deliberately omitted this feature rather than it being an oversight.

Why?

Edit: Ok so maybe this use case isn't as common as I had expected, so I'll illustrate my particular scenario. I have a machine learning algorithm which is distributed on multiple threads. Each thread operates asynchronously, and returns to a master pool once it has completed an optimisation problem.

It then locks a master mutex. The thread must then pick a new parent from which to mutate an offspring, but may only pick from parents which do not currently have offspring that are being optimised by other threads. I therefore need to perform a search to find parents that are not currently locked by another thread. There is no risk of the status of the mutex changing during the search, as the master thread mutex is locked. Obviously there's other solutions (I'm currently using a boolean flag) but I thought the mutex offers a logical solution to this problem, as it exists for the purpose of inter-thread synchronization.

  • 42
    You can't really reasonably check whether a mutex is locked, because one nanosecond after the check it can get unlocked or locked. So if you wrote "if (mutex_is_locked ()) ... " then mutex_is_locked could return the correct result, but by the time the "if" is executed, it is wrong. – gnasher729 Sep 11 '16 at 13:33
  • 1
    This^. What useful information do you hope to get from is_locked? – Useless Sep 11 '16 at 13:34
  • 3
    This feels like an XY-problem. Why are you trying to prevent reuse of the parents only while a child is being generated? Do you have a requirement that any parent may only have exactly one offspring? Your lock will not prevent that. Don't you have clear generations? If not, are you aware that individuals that can be optimized faster have higher fitness, since they can be selected more often/earlier? If you do use generations, why don't you select all parents up front, then let the threads retrieve parents from a queue? Is generating offspring really so expensive that you need multiple threads? – amon Sep 11 '16 at 14:01
  • 10
    @quant - I don't see why your parent object mutexes in your example application need to be mutexes at all: if you have a master mutex which is locked whenever they are set, you can just use a boolean variable to indicate their status. – Periata Breatta Sep 11 '16 at 14:12
  • 4
    I disagree with the last sentence of the question. A simple boolean value is far cleaner than a mutex here. Make it an atomic bool if you don't want to lock the master mutex for "returning" a parent. – Sebastian Redl Sep 12 '16 at 9:42
up vote 50 down vote accepted

I can see at least two severe problems with the suggested operation.

The first one was already mentioned in a comment by @gnasher729:

You can't really reasonably check whether a mutex is locked, because one nanosecond after the check it can get unlocked or locked. So if you wrote if (mutex_is_locked ()) … then mutex_is_locked could return the correct result, but by the time the if is executed, it is wrong.

The only way to be sure that the “is currently locked” property of a mutex doesn't change is to, well, lock it yourself.

The second problem I see is that unless you lock a mutex, your thread doesn't synchronize with the thread that had previously locked the mutex. Therefore, it isn't even well-defined to speak about “before” and “after” and whether the mutex is locked or not is kind of asking whether Schrödiger's cat is currently alive without attempting to open the box.

If I understand correctly, then both problems would be moot in your particular case thanks to the master mutex being locked. But this doesn't seem like a particularly common case to me so I think that the committee did the right thing by not adding a function that might be somewhat useful in very special scenarios and cause damage in all others. (In the spirit of: “Make interfaces easy to use correctly and difficult to use incorrectly.”)

And if I may say, I think that the setup you currently have is not the most elegant and could be refactored to avoid the problem altogether. For example, instead of the master thread checking all potential parents for one that is not currently locked, why not maintain a queue of ready parents? If a thread wants to optimize another one, it pops the next one off the queue and as soon as it has new parents, it adds them to the queue. That way, you don't even need the master thread as a coordinator.

  • Thanks, this is a good answer. The reason I do not want to maintain a queue of ready parents is that I need to preserve the order in which the parents were created (as this dictates their lifespan). This is easily done with a LIFO queue. If I start yanking things in and out I'd have to maintain a separate ordering mechanism that would complicate things, hence the current approach. – quant Sep 11 '16 at 14:37
  • 14
    @quant: If you have two purposes to queue parents, you can do so with two queues.... – Hurkyl Sep 11 '16 at 17:40
  • @quant: You're deleting an item (at most) once, but presumably doing processing on each multiple times, so you're optimizing the rare case at the expense of the common case. This is rarely desirable. – Jerry Coffin Sep 13 '16 at 2:00
  • 2
    But it is reasonable to ask whether the current thread has locked the mutex. – Limited Atonement May 18 at 19:20
  • @LimitedAtonement Not really. To do this mutex has to store additional information (thread id), making it slower. Recursive mutexes do this already, you should them instead. – Ivan Sep 6 at 12:04

It seems that you are using the secondary mutexes not to lock access to an optimisation problem, but to determine whether an optimisation problem is being optimised right now or not.

That is completely unnecessary. I'd have a list of problems that need optimising, a list of problems being optimised right now, and a list of problems that have been optimised. (Don't take "list" literally, take it to mean "any appropriate data structure).

The operations of adding a new problem to the list of unoptimised problems, or moving a problem from one list to the next, would be done under protection of the single "master" mutex.

  • 1
    You don't think that an object of type std::mutex is appropriate for such a data structure? – quant Sep 11 '16 at 18:31
  • 2
    @quant - no. std::mutex relies on an operating-system defined mutex implementation that may well take resources (e.g. handles) that are limited and slow to allocate and/or operate on. Using a single mutex to lock access to an internal data structure is likely to be much more efficient, and possibly more scalable too. – Periata Breatta Sep 11 '16 at 18:44
  • 1
    Also consider Condition Variables. They can make a lot of data structures like this really easy. – Cort Ammon Sep 12 '16 at 0:26

In addition to the two reasons given in 5gon12eder's answer above, I'd like to add that it is neither necessary nor desirable.

If you are already holding a mutex, then you had better know that you're holding it! You don't need to ask. Just like with owning a block of memory or any other resource, you should know exactly whether or not you own it, and when it's appropriate to release/delete the resource.
If that is not the case, your program is designed badly, and you are heading for trouble.

If you need to access the shared resource protected by the mutex, and you are not already holding the mutex, then you need to acquire the mutex. There's no other option, otherwise your program logic is not correct.
You might find blocking acceptable or inacceptable, in either case lock() or try_lock() will give the behavior you want. All you need to know, positively, and without doubt, is whether you successfully acquired the mutex (the return value of try_lock tells you). It's inconsequential whether someone else holds it or whether you got a spurious failure.

In every other case, bluntly, it's none of your business. You don't need to know, and you shouldn't know, or make assumptions (for the timeliness and sync issues mentioned in the other question).

  • 1
    What if I want to perform a ranking operation on the resources that are currently available for locking? – quant Sep 11 '16 at 16:40
  • But is that something that is realistic to happen? I'd deem that rather unusual. I would say either resources already have some intrinsic kind of ranking, then you will need to do (acquire the lock for) the more important one first. Example: Must update physics simulation prior to rendering. Or, the ranking is more or less deliberate, then you can as well try_lock the first resource, and if that one fails, try the second. Example: Three persistent, pooled connections to the database server, and you need to use one to send a command. – Damon Sep 11 '16 at 17:23
  • 4
    @quant - "a ranking operation on the resources that are currently available for locking" -- in general, doing this kind of thing is a really easy and quick way to write code that deadlocks in a way you struggle to figure out. Making locks acquisition and release deterministic is, in almost all cases, the best policy. Searching for a lock based on a criterion that could change is asking for trouble. – Periata Breatta Sep 11 '16 at 18:41
  • @PeriataBreatta My program is intentionally indeterminate. I see now that this attribute is not common, so I can understand the omission of features like is_locked() that might facilitate such behaviour. – quant Sep 11 '16 at 18:43
  • @quant ranking and locking are entirely separate problems. If you want to somehow sort or reorder a queue with a lock, lock it, sort it, then unlock it. If you need is_locked, then a much better solution to your problem exists than the one you have in mind. – Peter Sep 12 '16 at 18:33

As others said, there's no use case where is_locked on a mutex is of any benefit, that's why the function does not exist.

The case you're having a problem with is incredibly common, it's basically what worker threads do, which are one of the, if not the most common implementation of threads.

You have a shelf with 10 boxes on it. You have 4 workers working with these boxes. How do you make sure the 4 workers work on different boxes? The first worker takes a box off the shelf before they start working on it. The second worker sees 9 boxes on the shelf.

There are no mutexes to lock the boxes, so seeing the state of the imaginary mutex on the box is not necessary, and abusing a mutex as a boolean is just wrong. The mutex locks the shelf.

You may be wanting to use atomic_flag with the default memory order. It doesn't have data races and never throws exceptions like mutex does with multiple unlock calls (and aborts uncontrollably, I might add...). Alternatively, there is atomic (e.g. atomic[bool] or atomic[int] (with triangle brackets, not [])), which has nice functions like load and compare_exchange_strong.

I want to add a use-case for this: It would enable an internal function to ensure as a precondition / assertion that the caller is indeed holding the lock.

For classes with several such internal functions, and possibly many public functions calling them, it could ensure, that someone adding another public function calling the internal one did indeed acquire the lock.

class SynchronizedClass
{

public:

void publicFunc()
{
  std::lock_guard<std::mutex>(_mutex);

  internalFuncA();
}

// A lot of code

void newPublicFunc()
{
  internalFuncA(); // whops, forgot to acquire the lock
}


private:

void internalFuncA()
{
  assert(_mutex.is_locked_by_this_thread());

  doStuffWithLockedResource();
}

};

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.