Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CreateMutex & CloseHandle

951 views
Skip to first unread message

Aaron Brady

unread,
Mar 8, 2009, 4:32:26 AM3/8/09
to
Hi,

I am writing some synchronization functions. One function creates a
named mutex and acquires it (WaitForSingleObject). The second
releases it and closes it. The object may already exist elsewhere.

Is it necessary to keep the handle between calls? Or can I call
Create in the second one, and close it twice?

Norman Bullen

unread,
Mar 8, 2009, 11:36:04 AM3/8/09
to

Are you talking about two functions that are called in the same process
and thread? Or two different threads in the same process? Or two
different processes?

If you expect the mutex to remain locked (to prevent other processes
from acquiring it) the mutex handle must remain open and the mutex not
released until the second function is called.

If you don't pass the mutex handle to the second function, it will be
required to call CreateMutex() to get a NEW handle to the same mutex. It
will not be able to acquire ownership of the mutex through that handle
if it is in a different thread and it will not be able to close or
release the original handle.

If the second function is in a different process it will not be able to
acquire ownership of the mutex nor close the handle that is open in the
first process. Presumably the mutex remains locked by that process.

Since the second function need the original handle to the mutex in order
to close it, why bother with creating a new handle?

--
Norm

To reply, change domain to an adult feline.

Aaron Brady

unread,
Mar 8, 2009, 2:32:57 PM3/8/09
to
On Mar 8, 10:36 am, Norman Bullen <n...@BlackKittenAssociates.com>
wrote:

Very interesting. Any thread in any process can call these
functions. They have a key to the data they are accessing, and the
functions generate a (the) name for it. (I am using a graph to detect
deadlocks.)

acquire_by_cookie ( cookie ) {
char ownbuf[ 30 ];
sprintf_s( ownbuf, 30, "bycookie-%012X-own", cookie );
mutOwn= CreateMutex( NULL, FALSE, ownbuf );
WaitForSingleObject( mutOwn, INFINITE );
}

release_by_cookie( cookie /*, HANDLE? */ ) {
char ownbuf[ 30 ];
sprintf_s( ownbuf, 30, "bycookie-%012X-own", cookie );
/* ..... */
}

If I call CreateMutex in 'release_by_cookie', will I get the handle
that the same thread & proc. obtained in 'acquire_by_cookie'?
Presumably I can call 'ReleaseMutex' on it, and then close it *twice*.

boris

unread,
Mar 8, 2009, 8:14:51 PM3/8/09
to

"Aaron Brady" <casti...@gmail.com> wrote in message
news:14d2c95e-6228-44e8...@l16g2000yqo.googlegroups.com...

>>>>>>>>>>>>>>>
Hi,

I think you aren't clear of what WIN32 mutexes are and what's their
purpose - just read a book on WIN32 IPCs.
As Norman said, you can have multiple open handles to same mutex inside same
process (or inside multiple processes). Mutex will disappear when its last
open handle is closed (those handles can be spread across multiple
processes). The above applies not only to mutexes but also to event objects,
semaphores.
Specifically in case of mutexes - a mutex can be owned by only one thread at
a time; thread acquires mutex after WaitForSingleObject (called by that
thread) returns WAIT_OBJECT_0; thread releases mutex (that it previously
acquired) by calling ReleaseMutex.

Boris

boris

unread,
Mar 8, 2009, 8:57:58 PM3/8/09
to
> Hi,
>
> I think you aren't clear of what WIN32 mutexes are and what's their
> purpose - just read a book on WIN32 IPCs.
> As Norman said, you can have multiple open handles to same mutex inside
> same process (or inside multiple processes). Mutex will disappear when its
> last open handle is closed (those handles can be spread across multiple
> processes). The above applies not only to mutexes but also to event
> objects, semaphores.
To answer the question about multiple calls to CreateMutex or CreateEvent or
CreateSemaphore inside same process (specifying same name string as
parameter) - they will return same HANDLE. If 1st one is closed, 2nd one
becomes invalid (because it's same value). However, if HANDLE to mutex
(event, semaphore) is passed to DuplicateHandle - then 2 handles will be
different so that closing either one will not invalidate the remaining open
one.

Boris

Aaron Brady

unread,
Mar 9, 2009, 9:26:01 AM3/9/09
to

I'm proceeding with my design without the use of the shortcut. That
is, 'acquire' will return a handle, to be passed to 'release'.
However, since both functions know the name of the mutex, perhaps it
should not be necessary. Here is a reduced version of the snippet I
posted:

Create
Acquire (WaitForSingleObject)
Create
Release
Close

I think it should work though, shouldn't it? Of course, 'release' has
to be called by the same thread that owns the parameter.

Aaron Brady

unread,
Mar 9, 2009, 10:05:09 AM3/9/09
to

In a trial, the CloseHandle function returned 1 twice before returning
0. That means, Close needs to be called twice. A secondary thread
resumed as soon as the main one called 'Release', and Close returned 1
once in that.

In other words,

Create
Acquire (WaitForSingleObject)
Create
Release
Close

Close

is close to what I meant. However, in order for my goal to succeed,
which is to retrieve an mutex by name only which is already open and
owned by the same thread, I will not be able to close the handle I
open at first. By the time I am in the second 'Release' section, I
only have handle 2, even though it should be the same object. This is
the mysterious part:

h1= Create
Acquire( h1 ) // (WaitForSingleObject)
h2= Create
Release( h2 )
Close( h2 )
Close( h2 )

The second 'Close' succeeded! Is this an intended feature? Can I
rely on it? If so, it would be just the thing in my case.

boris

unread,
Mar 9, 2009, 6:55:36 PM3/9/09
to
By the time I am in the second 'Release' section, I
only have handle 2, even though it should be the same object. This is
the mysterious part:

h1= Create
Acquire( h1 ) // (WaitForSingleObject)
h2= Create
Release( h2 )
Close( h2 )
Close( h2 )

The second 'Close' succeeded! Is this an intended feature? Can I
rely on it? If so, it would be just the thing in my case.
>>>>>>>>

There're tools that allow you to see Win32 objects. For example, WinObj from
sysinternals.

Boris

Aaron Brady

unread,
Mar 9, 2009, 7:51:26 PM3/9/09
to

Hi, Boris,

Please disregard my post from earlier; I didn't read my output
closely.

'Create' retrieves a handle if the mutex bearing the specified name
exists already. The docs say, "subsequent processes with sufficient
access rights simply open a handle to the existing mutex". Therefore,
two creates opens two handles. However, each one needs to be closed
separately.

I need a way to close a mutex by name only, without keeping a record.
That is, create a mutex named "mutexXXX", then close one of the
handles my thread has to "mutexXXX", without keeping the handle from
creation-time. I should be able to, since they all refer to the same
object.

boris

unread,
Mar 10, 2009, 3:03:51 AM3/10/09
to
I need a way to close a mutex by name only, without keeping a record.
That is, create a mutex named "mutexXXX", then close one of the
handles my thread has to "mutexXXX", without keeping the handle from
creation-time. I should be able to, since they all refer to the same
object.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Hi,

I wrote some sample code that seems to be doing what you're looking for. It
uses some undocumented APIs that might change in future Windows. I only
tested in in 32-bit Vista SP1 - so don't know if it works in XP. That
questionable code: implementation of function MyGetMutexHandleAliases.
It works this way: instead of calling CloseHandle for some mutex handle, it
uses undocumented stuff to get list of handles associated with same kernel
object (in your case: a mutex) as input handle. Please notice that it only
returns handles that are valid inside current process, so if 2 processes
have opened handles to same mutex - this code will only return handles
associated with current process and the rest of the handles won't be
returned. Then the code (MyCloseAllMutexHandles function) calls CloseHandle
for each handle from the list.

The flow is like this:

Main thread creates mutex called BorisMutex (with handle mutex1) , then it
creates second thread and waits for that thread to end. After that it checks
if mutex1 is still a valid handle (by calling WaitForSingleObject: to
acquire the mutex - and then attempting to close it: via CloseHandle). 2nd
thread creates 2 more handles to same mutex (by calling CreateMutex with
same name parameter), then it closes all in-process handles to the mutex
(via code I described above: MyGetMutexHandleAliases and
MyCloseAllMutexHandles).

This code was written with VC2005 SP1: it won't compile in earlier versions
of VC++.

Boris

>>>>>SAMPLE CODE>>>>>>>>>>
#define _WIN32_WINNT 0x0500

#include <windows.h>
#include <process.h>
#include <stdio.h>

#include <winternl.h>
// Undocumented struct: single element of array returned by
NtQuerySystemInformation(SystemHandleInformation)
struct SYSTEM_HANDLE_INFORMATION_ENTRY
{
ULONG ProcessId;
UCHAR ObjectTypeNumber;
UCHAR Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
};
// Undocumented struct: the whole array returned by
NtQuerySystemInformation(SystemHandleInformation)
struct SYSTEM_HANDLE_INFORMATION
{
DWORD Count;
SYSTEM_HANDLE_INFORMATION_ENTRY Array[1];
};
// Undocumented element of SYSTEM_INFORMATION_CLASS enum
#define SystemHandleInformation 16
typedef NTSTATUS (WINAPI *PF_NtQuerySystemInformation)(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);

static LPCWSTR sMyMutexName=L"BorisMutex";

static unsigned __stdcall MyThreadFunc(void *);
static bool MyGetMutexHandleAliases(HANDLE handleVal, int *numHandles,
HANDLE **handles);
static bool MyCloseAllMutexHandles(int numHandles, HANDLE *handles);

void main()
{
HANDLE mutex1 = CreateMutex(0,FALSE,sMyMutexName);
if ( !mutex1 )
{
printf("Error creating mutex (in main thread): %d\n",
GetLastError());
exit(1);
}
else
{
wprintf(L"Successfully created mutex: %s, HANDLE value:
%x\n",sMyMutexName,mutex1);
}

HANDLE myThread = (HANDLE)_beginthreadex(0,0,MyThreadFunc,0,0,0);
if ( (HANDLE)-1 == myThread )
{
printf("Error creating thread\n");
exit(1);
}

WaitForSingleObject(myThread,INFINITE);

if ( WAIT_OBJECT_0 == WaitForSingleObject(mutex1,0) )
{
printf("Successfully acquired mutex in main thread - mutex handle is
still valid.\n");
ReleaseMutex(mutex1);
}
else
{
printf("Error acquiring mutex in main thread - mutex handle is
invalid.\n");
}

if ( CloseHandle(mutex1) )
{
printf("Successfully closed mutex handle (in main thread)\n");
}
else
{
printf("Error closing mutex handle (in main thread): %d\n",
GetLastError());
//exit(1);
}
}

static unsigned __stdcall MyThreadFunc(void *)
{
HANDLE mutex2 = CreateMutex(0,FALSE,sMyMutexName);
if ( !mutex2 )
{
printf("Error opening mutex 1st time (in 2nd thread): %d\n",
GetLastError());
exit(1);
}
else
{
wprintf(L"Successfully opened mutex: %s 1st time (in 2nd thread),
HANDLE value: %x\n",sMyMutexName,mutex2);
}

HANDLE mutex3 = CreateMutex(0,FALSE,sMyMutexName);
if ( !mutex3 )
{
printf("Error opening mutex 2nd time (in 2nd thread): %d\n",
GetLastError());
exit(1);
}
else
{
wprintf(L"Successfully opened mutex: %s 2nd time (in 2nd thread),
HANDLE value: %x\n",sMyMutexName,mutex3);
}

int numHandles = 0;
HANDLE *handles = NULL;
if ( MyGetMutexHandleAliases(mutex2, &numHandles, &handles) )
{
printf("Successfully got %d aliases for mutex handle
2\n",numHandles);
if ( MyCloseAllMutexHandles(numHandles,handles) )
{
printf("Successfully closed all aliases for mutex handle 2\n");
}
else
{
printf("Error closing some aliases for mutex handle 2\n");
}

free(handles);
}
else
{
printf("Error: Couldn't get aliases for mutex handle 2\n");
}

if ( WAIT_OBJECT_0 == WaitForSingleObject(mutex3,0) )
{
printf("Successfully acquired mutex in 2nd thread - mutex handle 3
is still valid.\n");
ReleaseMutex(mutex3);
}
else
{
printf("Error acquiring mutex in 2nd thread - mutex handle 3 is
invalid.\n");
}

if ( CloseHandle(mutex3) )
{
printf("Successfully closed mutex 3rd handle (in 2nd thread)\n");
}
else
{
printf("Error closing mutex 3rd handle (in 2nd thread): %d\n",
GetLastError());
}

return 0;
}

static bool MyCloseAllMutexHandles(int numHandles, HANDLE *handles)
{
for ( int idx = 0; idx < numHandles; idx++ )
{
if ( CloseHandle(handles[idx]) )
{
printf("Successfully closed mutex handle alias:
%x\n",handles[idx]);
}
else
{
printf("Error closing mutex mutex handle alias: %x, error code:
%d\n",handles[idx], GetLastError());
return false;
}
}

return true;
}

// This function should be tested on all OSes, because it uses undocumented
APIs that could change
static bool MyGetMutexHandleAliases(HANDLE handleVal, int *numHandles,
HANDLE **handles)
{
ULONG size = 0, sizeRequested = 0;
PVOID buf = NULL;

HMODULE hModNtDll = LoadLibrary(L"ntdll.dll");
if ( !hModNtDll )
{
printf("LoadLibrary for NtDll.dll failed\n");
exit(1);
}

PF_NtQuerySystemInformation pNtQuerySystemInformation =
(PF_NtQuerySystemInformation)GetProcAddress(hModNtDll,"NtQuerySystemInformation");
if ( !pNtQuerySystemInformation )
{
printf("GetProcAddress failed\n");
exit(1);
}

size = sizeof(SYSTEM_HANDLE_INFORMATION_ENTRY) * 100000; // 100000 is a
hack - is there any way of determining required size of output array?
buf = (PVOID) malloc(size);
if ( !buf )
{
printf("Error allocating %u bytes for temp buffer\n",size);
exit(1);
}

NTSTATUS status =
pNtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemHandleInformation,buf,size,&sizeRequested);
if ( status )
{
printf("Error: NtQuerySystemInformation failed: %x\n", status);
exit(1);
}

DWORD ourProcessId = GetCurrentProcessId();
SYSTEM_HANDLE_INFORMATION *pReturnedData = (SYSTEM_HANDLE_INFORMATION
*)buf;
PVOID pOurMutex = NULL;
// Step 1: get Object pointer that corresponds to handleVal
for ( DWORD idx = 0; idx < pReturnedData->Count; idx++)
{
if ( pReturnedData->Array[idx].ProcessId == ourProcessId &&
pReturnedData->Array[idx].Handle == (USHORT)handleVal )
{
pOurMutex = pReturnedData->Array[idx].Object;
break;
}
}

// Step 2: determine number of all handles associated with Object (as
determined during step 1)
// and the current process - required to know the size of output array.
*numHandles = 0;
for ( DWORD idx = 0; idx < pReturnedData->Count; idx++)
{
if ( pReturnedData->Array[idx].ProcessId == ourProcessId &&
pReturnedData->Array[idx].Object == pOurMutex )
{
(*numHandles)++;
}
}
*handles = (HANDLE*) malloc(sizeof(HANDLE) * (*numHandles));
if ( !*handles )
{
printf("Error allocating storage for output array of %d
handles\n",*numHandles);
exit(1);
}
memset(*handles,0,sizeof(HANDLE) * (*numHandles));

// Step 3: fill the output array with handles of interest
for ( DWORD idx = 0, idxHandle = 0; idx < pReturnedData->Count; idx++)
{
if ( pReturnedData->Array[idx].ProcessId == ourProcessId &&
pReturnedData->Array[idx].Object == pOurMutex )
{
(*handles)[idxHandle] =
(HANDLE)pReturnedData->Array[idx].Handle;
idxHandle++;
}
}

free(buf);

return true;
}


boris

unread,
Mar 10, 2009, 3:41:22 AM3/10/09
to
Forgot to mention:

The sample code is C++ - not C.
The sample code isn't very clean: validity of input parameters not checked,
etc.
I have Platform SDK installed: not sure if the sample code will compile with
just VC2005 SP1.

Boris

Aaron Brady

unread,
Mar 10, 2009, 10:44:02 AM3/10/09
to

Boris, Hi.

Bad luck. You got error 6 "ERROR_INVALID_HANDLE" on XP Home. (Try
again soon.;) However, the line breaks were broken which I fixed, I
added #define UNICODE, and the same result whether I had #define
_WIN32_WINNT 0x0500 or 0x0501 or not. Tried on VS 2008 9.0.30729.1
SP VC++ 2008 Express, XP Home 2002 SP 3.

I have an answer to your question:


// 100000 is a hack - is there any way of determining required size of
output array?

Yes.
ReturnLength [out, optional]

An optional pointer to a location where the function writes the
actual size of the information requested. If that size is less than or
equal to the SystemInformationLength parameter, the function copies
the information into the SystemInformation buffer; otherwise, it
returns an NTSTATUS error code and returns in ReturnLength the size of
buffer required to receive the requested information.
http://msdn.microsoft.com/en-us/library/ms724509(VS.85).aspx

I have your output here:

Successfully created mutex: BorisMutex, HANDLE value:7f4
Successfully opened mutex: BorisMutex 1st time (in 2nd thread),HANDLE
value: 7d4
Successfully opened mutex: BorisMutex 2nd time (in 2nd thread),HANDLE
value: 7d0
Successfully got 3 aliases for mutex handle 2
Successfully closed mutex handle alias: 7d0
Successfully closed mutex handle alias: 7d4
Successfully closed mutex handle alias: 7f4


Successfully closed all aliases for mutex handle 2

Error acquiring mutex in 2nd thread - mutex handle 3 is invalid.

Error closing mutex 3rd handle (in 2nd thread): 6


Error acquiring mutex in main thread - mutex handle is invalid.

Error closing mutex handle (in main thread): 6

However, the close operations succeeded. Very peculiar. So, mixed
results.

boris

unread,
Mar 10, 2009, 12:22:52 PM3/10/09
to

"Aaron Brady" <casti...@gmail.com> wrote in message
news:33f6bb25-5c09-4668...@b38g2000prf.googlegroups.com...

Hi Aaron,

Boris, Hi.

Bad luck. You got error 6 "ERROR_INVALID_HANDLE" on XP Home. (Try
again soon.;) However, the line breaks were broken which I fixed, I
added #define UNICODE, and the same result whether I had #define
_WIN32_WINNT 0x0500 or 0x0501 or not. Tried on VS 2008 9.0.30729.1
SP VC++ 2008 Express, XP Home 2002 SP 3.

I have an answer to your question:
// 100000 is a hack - is there any way of determining required size of
output array?
Yes.
ReturnLength [out, optional]

[boris] I tried using it: specified size of 0 and got some small number for
ReturnLength (30 or so) - didn't work for me.

An optional pointer to a location where the function writes the
actual size of the information requested. If that size is less than or
equal to the SystemInformationLength parameter, the function copies
the information into the SystemInformation buffer; otherwise, it
returns an NTSTATUS error code and returns in ReturnLength the size of
buffer required to receive the requested information.
http://msdn.microsoft.com/en-us/library/ms724509(VS.85).aspx

I have your output here:

Successfully created mutex: BorisMutex, HANDLE value:7f4
Successfully opened mutex: BorisMutex 1st time (in 2nd thread),HANDLE
value: 7d4
Successfully opened mutex: BorisMutex 2nd time (in 2nd thread),HANDLE
value: 7d0
Successfully got 3 aliases for mutex handle 2
Successfully closed mutex handle alias: 7d0
Successfully closed mutex handle alias: 7d4
Successfully closed mutex handle alias: 7f4
Successfully closed all aliases for mutex handle 2
Error acquiring mutex in 2nd thread - mutex handle 3 is invalid.
Error closing mutex 3rd handle (in 2nd thread): 6
Error acquiring mutex in main thread - mutex handle is invalid.
Error closing mutex handle (in main thread): 6

[boris] It works as expected. After undocumented code closed all handles -
these lines:

Successfully got 3 aliases for mutex handle 2
Successfully closed mutex handle alias: 7d0
Successfully closed mutex handle alias: 7d4
Successfully closed mutex handle alias: 7f4
Successfully closed all aliases for mutex handle 2

- acquiring and closing via "normal" code fails - so it seems fine on XP.

Boris

0 new messages