tags:

views:

118

answers:

3

The MSDN CreatMutex() documentation (http://msdn.microsoft.com/en-us/library/ms682411%28VS.85%29.aspx) contains the following remark near the end:

Two or more processes can call CreateMutex to create the same named mutex. The first process actually creates the mutex, and subsequent processes with sufficient access rights simply open a handle to the existing mutex. This enables multiple processes to get handles of the same mutex, while relieving the user of the responsibility of ensuring that the creating process is started first. When using this technique, you should set the bInitialOwner flag to FALSE; otherwise, it can be difficult to be certain which process has initial ownership.

Can somebody explain the problem with using bInitialOwner = TRUE?

Earlier in the same documentation it suggests a call to GetLastError() will allow you to determine whether a call to CreateMutex() created the mutex or just returned a new handle to an existing mutex:

Return Value

If the function succeeds, the return value is a handle to the newly created mutex object.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

If the mutex is a named mutex and the object existed before this function call, the return value is a handle to the existing object, GetLastError returns ERROR_ALREADY_EXISTS, bInitialOwner is ignored, and the calling thread is not granted ownership. However, if the caller has limited access rights, the function will fail with ERROR_ACCESS_DENIED and the caller should use the OpenMutex function.

+1  A: 

Well, not sure if there's a real problem. But if you set the argument to TRUE in both processes then you have to check the value of GetLastError() to check if you actually ended up having ownership. It will be first-come-first serve. Useful perhaps only if you use a named mutex to implement a singleton process instance.

Hans Passant
A: 

The flag is used to create the mutex in an owned state - the successful caller will atomically create the synchronisation object and also acquire the lock before returning in the case that the caller needs to be certain that no race condition can form between creating the object and acquiring it.

Your protocol will determine whether you ever need to do this in one atomic operation.

Pekka
+1  A: 

Using bInitialOwner combines two steps into one: creating the mutex and acquiring the mutex. If multiple people can be creating the mutex at once, the first step can fail while the second step can succeed.

As the other answerers mentioned, this isn't strictly a problem, since you'll get ERROR_ALREADY_EXISTS if someone else creates it first. But then you have to differentiate between the cases of "failed to create or find the mutex" and "failed to acquire the mutex; try again later" just by using the error code. It'll make your code hard to read and easier to screw up.

In contrast, when bInitialOwner is FALSE, the flow is much simpler:

result = create mutex()
if result == error:
   // die
result = try to acquire mutex()
if result == error:
   // try again later
else:
   // it worked!
apenwarr
In the situation I'm working with several copies of the same process are started which need to synchronize their logging via this mutex.I want the first process that starts to clear the log, so I was hoping that if bInitialMutex == TRUE then the process for which the call succeeds (and which does not get ERROR_ALREADY_EXISTS) would be the first process.
Tom Williams
Nice. In that case I'd agree with you: your use case is probably simpler with bInitialMutex=TRUE, since you exactly want a special case for the doesn't-exist-and-I-acquired-it situation.
apenwarr