/* wmutex2.c */
#include <windows.h>
#include <stdio.h>

unsigned int Count;

struct ThreadParams
{
  HANDLE mutex;
  int tid;
};

DWORD WINAPI ThreadFn(LPVOID p)
{
  int i;
  struct ThreadParams *params = (struct ThreadParams *)p;
  HANDLE mutex = params->mutex;
  
  for (i = 0; i < 1000 * 1000; i++)
  {
    WaitForSingleObject(mutex, INFINITE);
      Count++;
    ReleaseMutex(mutex);
  }
  
  return TRUE;
}

int main(int argc, char **argv)
{
  int i;
  HANDLE *threads;
  struct ThreadParams* params;  
  DWORD ThreadID;
  HANDLE mutex;
  int num_threads = 12;

    /* The user can specify the number of threads */  
  if (argc > 1)
    num_threads = atoi(argv[1]);

    /* Allocate memory for threads and parameters */    
  threads = malloc(num_threads * sizeof(HANDLE));
  params = malloc(num_threads * sizeof(struct ThreadParams));
  
    /* Create mutex */  
  mutex = CreateMutex(NULL, FALSE, NULL);
  if (mutex == NULL) 
  {
    printf("Error creating mutex: %d\n", GetLastError());
    return -1;
  }

    /* Create the threads */
  for(i = 0; i < num_threads; i++)
  {
    params[i].mutex = mutex;
    params[i].tid = i;
    
    threads[i] = CreateThread(NULL, 0, ThreadFn, &params[i], 0, &ThreadID); 
    if(threads[i] == NULL)
    {
      printf("Error creating thread: %d\n", GetLastError());
      return -1;
    }
  }

    /* Wait for each thread */
  WaitForMultipleObjects(num_threads, threads, TRUE, INFINITE);
  
    /* Release thread handles */
  for(i = 0; i < num_threads; i++)
    CloseHandle(threads[i]);

    /* Release mutex */
  CloseHandle(mutex);
  
  printf("Value of Count is %u\n", Count);
  
    /* Clean up memory */
  free(threads);
  free(params);

  return 0;
}