Thursday, September 17, 2015

Understanding Mutex entity

Studying example from MSDN article Using Mutex Objects some questions arise about mutex entity.
Here are experimentally proved suggestions:
  1. Mutexes are like files, open and create them with CreateMutex, close with CloseHandle (for files you use CreateFile, CloseHandle)
  2. Unnamed mutex is like critical section
  3. Mutexes are deleted after CloseHandle when no application currently have them opened
You can understand these things from running 10 simple programs which in short do the following:
HANDLE h
main(){
  h = CreateMutex("Global\\SuperMutex")
  CreateThread(WriteToDatabase)
  CloseHandle(h)
}

WriteToDatabase()
{
  WaitForSingleObject(h)
  ReleaseMutex(h)
}
Some programs create h = 0x3c, some h = 0x44
Some create mutex via CreateMutex while having ERROR_ALREADY_EXISTS

Pic 1. Running 10 of these programs:


Example sources are here...

Run them with .bat script:
@echo off
start UsingMutex.exe
start UsingMutex.exe
start UsingMutex.exe
start UsingMutex.exe
start UsingMutex.exe
start UsingMutex.exe
start UsingMutex.exe
start UsingMutex.exe
start UsingMutex.exe
start UsingMutex.exe
UsingMutex.cpp itself:
#include <windows.h>
#include <stdio.h>
#include <conio.h>

#define THREADCOUNT 2
#define WRITE_ATTEMPTS 5
#define MUTEXNAME "Global\\SuperMutex"

HANDLE ghMutex;

DWORD WINAPI WriteToDatabase( LPVOID );

void main()
{
   HANDLE aThread[THREADCOUNT];
   DWORD thid;
   int i;
   ghMutex = CreateMutex(NULL, FALSE, MUTEXNAME);
   //ghMutex = OpenMutex(NULL, FALSE, MUTEXNAME);
   if (ghMutex==NULL) {
      DWORD dw = GetLastError();
      if (dw == ERROR_FILE_NOT_FOUND)
         printf("CreateMutex error ERROR_FILE_NOT_FOUND\n");
      else if (dw == ERROR_ACCESS_DENIED)
         printf("CreateMutex error ERROR_ACCESS_DENIED\n");
      else if (dw == ERROR_INVALID_HANDLE)
         printf("CreateMutex error ERROR_INVALID_HANDLE\n");
      else
         printf("CreateMutex error %d\n", dw);
      return;
   }
   if (GetLastError() == ERROR_ALREADY_EXISTS)
   {
      printf("CreateMutex error ERROR_ALREADY_EXISTS\n");
   }
   printf("Created Mutex 0x%x\n", ghMutex);

   for(i=0; i<THREADCOUNT; i++)
   {
      aThread[i]=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WriteToDatabase, NULL, 0, &thid);
      if(aThread[i] == NULL) {
         printf("CreateThread error: %d\n", GetLastError());
         return;
      }
   }
   WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);

   for(i=0; i<THREADCOUNT; i++)
      CloseHandle(aThread[i]);
   CloseHandle(ghMutex);
 
   printf("Press Any Key to continue...\n");
   getch();
}

DWORD WINAPI WriteToDatabase( LPVOID )
{
   DWORD dwCount=0, dwWaitResult;

   while(dwCount<WRITE_ATTEMPTS)
   {
      dwWaitResult = WaitForSingleObject(ghMutex, INFINITE);
      switch(dwWaitResult)
      {
      case WAIT_OBJECT_0:
         __try {
            printf("Thread % d writing to database...\n", GetCurrentThreadId());
            dwCount++;
         }
         __finally{
            printf("Thread % d finished\n", GetCurrentThreadId());
            if (!ReleaseMutex(ghMutex))
            {
               //TODO
            }
         }
         break;
      case WAIT_ABANDONED:
         return FALSE;
      }
   }
   return TRUE;
}

No comments:

Post a Comment