We help IT Professionals succeed at work.

How to check for current mutex ownership

Beth2
Beth2 asked
on
I am using a mutex that must remain locked across several function calls.  Thus, it cannot be taken and then released at the beginning and end of each function, respectively.  Thus, I am looking for a method to determine if I currently have ownership of a mutex.  I had hoped that the WaitForSingleObject function would provide this information to me.  However, from the documentation I have read, it appears that the code would indeed wait even if it had ownership.

Some additional information that might prove helpful:
- writing in C
- using CreateMutex/ReleaseMutex methods

Can anyone tell me how to check for ownership?

thanks!
Comment
Watch Question

CERTIFIED EXPERT
Top Expert 2012
Commented:
>>Can anyone tell me how to check for ownership?

The only method I can think of that is 'portable' would be using a wait operation that times out:

BOOL IsMutexOwned ( HANDLE hMutex) {

 DWORD dwWaitResult = WaitForSingleObject ( hMutex, 1);

 return ( WAIT_TIMEOUT == dwWaitResult);
}

...however, you need to release the mutex, if the wait was successful.

You could go with a wrapper (Pseudocode!)


class CMyMutex
{
  bool haveMutex;
  HANDLE mutex;

  bool HasMutex() { return haveMutex; }

  void Wait()
  {
    if (haveMutex)
       return;
    if (WaitForSingleObject == WAIT_OBJECT_0) {
      haveMutex = true;
    }
  }

  void Release()
  {
    if (haveMutex) {
      haveMutex = false;
      ReleaseMutex(mutex);
    }
  }
};

However, each thread needs it's own instance of this class. And you should add the "vanilla" stuff (correct CTor/DTor etc.)


Peter
Commented:
Yep, both jkr and Peter are right. Using WaitForSingleObject is the way to go (in connection with a ReleaseMutex call, if WaitForSingleObject returned WAIT_OBJECT_0). However, one little addition: You don't need to call WaitForSingleObject with 1 millisecond. Usually in such a case you simply give in 0 as the timeout time. That works fine and doesn't have any delay in case the mutex is locked.

Regards, Madshi.
>>However, from the documentation I have read, it appears
that the code would indeed wait even if it had ownership.

Wrong. The docs say:

<<While a thread has ownership of a mutex, it can specify the same mutex in additional wait-function calls without blocking its execution. This prevents a thread from deadlocking itself while waiting for a mutex that it already owns. However, to release its ownership, the thread must call ReleaseMutex once for each time that the mutex satisfied a wait.>>

So you have two options:

First -----------------------------------

WaitFor...(hMutex)
func1()
func2()
func3()
ReleaseMutex(hMutex)

Second -----------------------------------

func1()
{
WaitFor...(hMutex)
func2()
ReleaseMutex(hMutex)
}


func2()
{
WaitFor...(hMutex)
func3()
ReleaseMutex(hMutex)
}


func3()
{
WaitFor...(hMutex)
// some stuff
ReleaseMutex(hMutex)
}



Author

Commented:
Thanks for the very helpful comments.  

BUT...
I only want to enter the guarded section if I already own the mutex.  I don't want to enter it if the mutex is 1. owned by another process (easy enough) or 2. not already owned by me (appears to be somewhat harder).  Thus, waiting for the mutex is not sufficient.  I need to know the state.  If WaitForSingleObject was helpful enough to return a code letting me know "Hey dummy, you already have this one!", everything would be fine.  I can't simply try a timeout of 0 because the mutex might simply be free.  Again, a free mutex is not sufficient, the process must current own it.

I see that I did not previously mention that the methods whose functionality must be guarded are utility functions.  Thus, it is somewhat difficult to force option 1 as provided by Nick.  Option 2 is highly preferable.

Commented:
>> I only want to enter the guarded section if I already own the mutex.

Okay, how about this suggestion?

Initialization:

(1) Create a named mutex.
(2) Create a named memory mapped file (no real file, only in memory -> CreateFileMapping(-1, ...)) with 4 bytes length.

Entering the mutex:

(1) Call WaitForSingleObject(mutexHandle, INFINITE) to own the mutex.
(2) Once you own it, write your threadID into the named memory mapped file buffer.
(3) Do whatever you want.
(4) Write a dummy threadID (e.g. 0) into the memory mapped buffer.
(5) Release the mutex.

Checking for ownership:

(1) Check whether the named buffer contains your threadID.

With this logic you can from every process system wide access this memory mapped file buffer and check which thread currently owns the mutex.
Of course due to the nature of multitasking you cannot really rely on this information. It can change in the moment where you access the buffer. However, you CAN rely on one thing: If you own the mutex yourself, then the memory mapped buffer will contain your threadID, otherwise it will not.

Regards, Madshi.

Commented:
but something i don't get in all your posts:
waitforsingleobject will definitely not wait if you already own the mutex, i mean, that's the only thing why you use mutexes and not events!
a mutex you can own "as many times" as you like, it has an internal counter which is increased everytime a waitforxxxobjectxx method returns. so you don't event need to check if you own it, just wait for it before all you operations once, then you _can_ wait for it at the beginning on all your procedures again (which will immediately return and increase the mutexes-counter) and release it at the end of all your procedures (decrement the mutexes counter). release it once again after you had called the procedures you desire, and all will be fine.
i mean, if you would use an event, you'd have to do all the stuff mentioned, but not with mutexes.
check sdk "ReleaseMutex" or "CreateMutex" if ya don't believe me, but you can never deadlock yourself with a mutex.
jkr
CERTIFIED EXPERT
Top Expert 2012

Commented:
>>waitforsingleobject will definitely not wait if you already own the mutex

And the return value will _not_ be WAIT_TIMEOUT then :o)

Commented:
the whole thing about checking if one ownes a mutex is nonsense if ya ask me, because you can

var mutex: integer;

procedure doit1;
begin
waitforsingleobject(mutex, infinite);
dowhatever;
releasemutex(mutex);
end;

procedure doit2;
begin
waitforsingleobject(mutex, infinite);
dowhatever2;
releasemutex(mutex);
end;

procedure doitwith1and2;
begin
waitforsingleobject(mutex, infinite);
doit1;
doit2;
releasemutex(mutex);
end;