Using Mutex Objects Program Example
You can use a mutex object to protect a shared resource from simultaneous access by multiple threads or processes. Each thread must wait for ownership of the mutex before it can execute the code that accesses the shared resource. For example, if several threads share access to a database, the threads can use a mutex object to permit only one thread at a time to write to the database. The following example uses the CreateMutex() function to create a mutex object and the CreateThread() function to create worker threads. When a thread of this process writes to the database, it first requests ownership of the mutex using the WaitForSingleObject() function. If the thread obtains ownership of the mutex, it writes to the database and then releases its ownership of the mutex using the ReleaseMutex() function. This example uses structured exception handling to ensure that the thread properly releases the mutex object. The __finally block of code is executed no matter how the __try block terminates (unless the __try block includes a call to the TerminateThread() function). This prevents the mutex object from being abandoned inadvertently. If a mutex is abandoned, the thread that owned the mutex did not properly release it before terminating. In this case, the status of the shared resource is indeterminate, and continuing to use the mutex can obscure a potentially serious error. Some applications might attempt to restore the resource to a consistent state; this example simply returns an error and stops using the mutex.
Create a new empty Win32 console application project. Give a suitable project name and change the project location if needed.
Then, add the source file and give it a suitable name.
Next, add the following source code.
#include <windows.h>
#include <stdio.h>
#define THREADCOUNT 2
HANDLE ghMutex;
DWORD WINAPI WriteToDatabase(LPVOID);
void wmain()
{
HANDLE aThread[THREADCOUNT];
DWORD ThreadID;
int i;
DWORD Ret;
// Create a mutex with no initial owner
ghMutex = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
NULL); // unnamed mutex
if (ghMutex == NULL)
{
wprintf(LCreateMutex() failed, error %d\n, GetLastError());
return;
}
else
wprintf(LCreateMutex() is Ok\n);
// Create worker threads
wprintf(LCreating the worker threads...\n);
for( i=0; i < THREADCOUNT; i++ )
{
aThread[i] = CreateThread(
NULL, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE) WriteToDatabase,
NULL, // no thread function arguments
0, // default creation flags
&ThreadID); // receive thread identifier
if( aThread[i] == NULL )
{
wprintf(LCreateThread() failed, error: %d\n, GetLastError());
return;
}
else
wprintf(LCreateThread() #%i is OK\n, i);
}
// Wait for all threads to terminate
// WAIT_OBJECT_0, WAIT_ABANDONED_0, WAIT_TIMEOUT, WAIT_FAILED
Ret = WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);
wprintf(LWaitForMultipleObjects() return value is %d\n, Ret);
// Close thread and mutex handles
for( i=0; i < THREADCOUNT; i++ )
{
if(CloseHandle(aThread[i]) != 0)
wprintf(LThread %d handle was successfully closed...\n, GetCurrentThreadId());
else
wprintf(LFailed to close thread %d handle...\n, GetCurrentThreadId());
}
CloseHandle(ghMutex);
}
DWORD WINAPI WriteToDatabase(LPVOID lpParam )
{
DWORD dwCount=0, dwWaitResult;
// Request ownership of mutex.
while( dwCount < 20 )
{
dwWaitResult = WaitForSingleObject(
ghMutex, // handle to mutex
INFINITE); // no time-out interval
switch (dwWaitResult)
{
// The thread got ownership of the mutex
case WAIT_OBJECT_0:
__try {
// TODO: Write to the database
wprintf(LThread %d writing to database, count #%d\n, GetCurrentThreadId(), dwCount);
dwCount++;
}
__finally {
// Release ownership of the mutex object
if (! ReleaseMutex(ghMutex))
{
// Handle error.
}
}
break;
// The thread got ownership of an abandoned mutex
// The database is in an indeterminate state
case WAIT_ABANDONED:
return FALSE;
}
}
return TRUE;
}
Build and run the project. The following screenshot is a sample output.