Using Mutex Objects

< BACK  NEXT >
[oR]

Mutex (or "Mutual Exclusion") kernel objects are used to ensure that global variables or resources are accessed exclusively by a piece of code. In this respect, they provide the same functionality as critical sections. However, they are more flexible. For example, critical sections can only be used to ensure exclusivity within a single process, whereas mutex objects can be used across processes.

The following steps are required when using mutex kernel objects:

  • Create a new mutex or open an existing mutex by calling the function CreateMutex.

  • Call WaitForSingleObject when entering critical code.

  • Call ReleaseMutex when the critical code execution is complete.

  • Call CloseHandle on the mutex when the mutex is no longer required.

Like all kernel objects, a mutex can either be signaled (in which case WaitForSingleObject will not block), or non-signaled (in which case WaitForSingleObject will block until the object becomes signaled). The function ReleaseMutex changes the mutex state from signaled to non-signaled.

Table 6.3. CreateMutex Creates a new mutex or opens an existing mutex
CreateMutex
LPSECURITY_ATTRIBUTES lpMutexAttributes Not supported, pass as NULL.
BOOL bInitialOwner TRUE if the object is created signaled, and will be owned by the thread creating the mutex. FALSE if the object is to be created non-signaled. The value is ignored if an existing mutex is being opened.
LPCTSTR lpName String containing name of mutex, or NULL if an unnamed mutex is being created. If this parameter is NULL a new mutex is always created.
HANDLE Return Value Handle to new or existing mutex, or NULL on failure. GetLastError returns ERROR_ALREADY_EXISTS if an existing mutex was opened.

A thread owns a mutex from the time the thread's call to WaitForSingleObject returns until the thread calls ReleaseMutex. In other words, the thread owns the mutex while the mutex is signaled. A mutex can be initially created:

  • Signaled. In this case, the thread that creates the mutex owns the mutex. All other threads calling WaitForSingleObject will block until the thread that owns the mutex calls ReleaseMutex.

  • Non-signaled. The thread that creates the mutex does not own the mutex in fact, no thread owns the mutex. The first thread that calls WaitForSingleObject will not block and will take ownership of the mutex.

A thread that owns a mutex can terminate before calling ReleaseMutex. In this case, the next thread to call WaitForSingleObject will take ownership of the mutex. However, WaitForSingleObject will return WAIT_ ABANDONED rather than WAIT_OBJECT_0.

Table 6.4. ReleaseMutex Changes a mutex's state to non-signaled
ReleaseMutex
HANDLE hMutex Handle of the mutex to change to non-signaled
BOOL Return Value TRUE on success, otherwise FALSE

Listing 6.2 shows how to use a mutex to control access to a global variable. The code performs the same function as Listing 6.1 but uses a mutex instead of a critical section. The mutex is created by calling CreateMutex, and the second parameter ("TRUE") specifies that that mutex is owned by the thread that creates it. Any other thread that calls WaitForSingleObject will block until the thread that created the mutex calls ReleaseMutex. In Listing 6.2, each thread calls WaitForSingleObject before accessing the global variable g_fValueMutex. One of the thread functions fc1 or fc2 will unblock when the function Listing 6_2 calls ReleaseMutex. The other function will unblock when ReleaseMutex is called by the other unblocked thread function.

Listing 6.2 Using a mutex
 float g_fValueMutex = 10.0; DWORD WINAPI fc1(LPVOID); DWORD WINAPI fc2(LPVOID); HANDLE hMutex; void Listing6_2() {   HANDLE hThread1, hThread2;   DWORD dwThreadID;   g_fValueMutex = 10.0;   // Create mutex that's initially owned by this thread   hMutex = CreateMutex(NULL, TRUE, NULL);   hThread1 = CreateThread(NULL, 0,       fc1, NULL, 0, &dwThreadID);   hThread2 = CreateThread(NULL, 0,       fc2, NULL, 0, &dwThreadID);   // Release Mutex to allow both threads to   // execute their code.   ReleaseMutex(hMutex);   // Wait until thread 1 and thread 2 completes   WaitForSingleObject(hThread1, INFINITE);   WaitForSingleObject(hThread2, INFINITE);   // Close handle for the mutex and threads   CloseHandle(hMutex);   CloseHandle(hThread1);   CloseHandle(hThread2);   cout    _T("Finished:")   g_fValueMutex    endl; } DWORD WINAPI fc1(LPVOID) {   WaitForSingleObject(hMutex, INFINITE);   g_fValueMutex = g_fValueMutex * g_fValueMutex;   ReleaseMutex(hMutex);   return 0; } DWORD WINAPI fc2(LPVOID) {   WaitForSingleObject(hMutex, INFINITE);   g_fValueMutex = (float)3.0 + g_fValueMutex;   ReleaseMutex(hMutex);   return 0; } 

The function CreateMutex allows the mutex to be named the last parameter is a string pointer to the mutex's name. If CreateMutex is called with the name of an existing mutex, the existing mutex will be opened rather than creating a new mutex. In this case, CreateMutex returns success, but GetLastError will return ERROR_ALREADY_EXISTS. Many processes can use a named mutex, so this allows mutual exclusion between processes. Windows CE does not support the Win32 function OpenMutex; however, all the functionality of OpenMutex is available through CreateMutex. Listing 4.25 in Chapter 4 ("Property Databases and the Registry") shows how to use a named mutex.


< BACK  NEXT >


Windows CE 3. 0 Application Programming
Windows CE 3.0: Application Programming (Prentice Hall Series on Microsoft Technologies)
ISBN: 0130255920
EAN: 2147483647
Year: 2002
Pages: 181

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net