2

A function is doing things on variables that must be protected against concurrent threads by a mutex.
The caller of this function locks a mutex, performs other things and calls this function.

Now a situation arised that requires this function to be called from another piece of code.
Of course this code could lock the mutex too but I thought perhaps the function could see if it must lock the mutex or not.

What I would need is a function that tells me if the current thread has locked the mutex. Then the function could go on without locking. Otherwise it would lock.

int need_to_lock = !my_thread_has_locked_the_mutex(&mutex);

if (need_to_lock)
    mutex_lock(&mutex);

access variables;

if (need_to_lock)
    mutex_unlock(&mutex);

Does my_thread_has_locked_the_mutex exist? I couldn't find anything.

Edit to comments

I didn't know about recursive mutexes. They seem to do what I thought of.
What I use now is a not recursive mutex that blocks if locked twice from the same thread.

Droidum
  • 440
  • 2
  • 9
  • 3
    You could just use a [recursive mutex](https://stackoverflow.com/a/7963765) – Mike van Dyke Feb 27 '20 at 13:03
  • 1
    If you're in the same thread, there is no harm in locking again (see: "recursive mutex"). If another thread has locked, then your thread will wait to lock, which is exactly the point of a mutex. The situation you propose where you check-then-act is a race condition in the making, since another thread could lock/unlock between the check and the action. – Edd Inglis Feb 27 '20 at 13:04
  • 1
    ... and that general idiom is pretty common: instead of checking before doing something with cross-thread dependencies, one simply tries (using an API that supports this) and checks *afterward* whether it worked. Details vary, of course, including whether the attempt may block, but the general pattern applies to substantially all synchronization operations and many atomic operations. And really, it's a standard idiom even for single-threaded code: look at how many functions' return values convey information including whether the function succeeded or failed. – John Bollinger Feb 27 '20 at 13:11
  • "since another thread could lock/unlock between the check and the action" - yes another thread could lock in this moment, but that wouldn't harm because then my function waits as the mutex expects. The only point is if my thread already has the mutex then I wouldn't have to lock on it again. – Droidum Feb 27 '20 at 13:40

1 Answers1

3

Why not just use a recursive mutex instead? A recursive mutex is substantially similar to a regular mutex, but can be locked multiple times by a single thread (i.e. recursively).

In some libraries, mutexes are recursive by default. With C pthreads, you need to opt in to recursive mutexes by initializing your mutexes appropriately:

pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(mutex, &attr);

Another approach is to split your function into two variants: one that should be called with the mutex held, and one that should be called without the mutex held. The usual naming convention is to append _locked to the former, or _unlocked to the latter. The unlocked function simply locks the mutex and then calls the locked function, so there won’t be any real duplication of code here.

nneonneo
  • 171,345
  • 36
  • 312
  • 383