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

unsigned int Count;

struct ThreadParams
{
  CRITICAL_SECTION *critical_section;
  int tid;
};

DWORD WINAPI ThreadFn(LPVOID p)
{
  int i;
  struct ThreadParams *params = (struct ThreadParams *)p;
  CRITICAL_SECTION *critical_section = params->critical_section;

  for (i = 0; i < 1000 * 1000; i++)
  {
    EnterCriticalSection(critical_section);
      Count++;
    LeaveCriticalSection(critical_section);
  }
  
  return TRUE;
}

int main(int argc, char **argv)
{
  int i;
  HANDLE *threads;
  struct ThreadParams* params;  
  DWORD ThreadID;
  CRITICAL_SECTION critical_section;
  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));
  
    /* Setup critical section */  
  InitializeCriticalSection(&critical_section);

    /* Create the threads */
  for(i = 0; i < num_threads; i++)
  {
    params[i].critical_section = &critical_section;
    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 critical section */
  DeleteCriticalSection(&critical_section);
  
  printf("Value of Count is %u\n", Count);
  
    /* Clean up memory */
  free(threads);
  free(params);

  return 0;
}