//================================================= file = semaphore2.c =====
//=  A simple bare-bones example of Windows semaphores and threads          =
//===========================================================================
//=  Notes:                                                                 =
//=    1) This program demonstrates how a semaphore can be used to          =
//=       periodically pause a thread (from a timing thread).               =
//=    2) Need to set T_ON and T_OFF in #define                             =
//=    3) Ignore two compile-time warnings on unused parameter              =
//=-------------------------------------------------------------------------=
//= Example execution: (T_ON = 2000, T_OFF = 5000)                          =
//=                                                                         =
//=    1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20           =
//=   21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40           =
//=   41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60           =
//=   61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80           =
//=   81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100          =
//=-------------------------------------------------------------------------=
//=  Build: bcc32 -WM semaphore2.c                                          =
//=-------------------------------------------------------------------------=
//=  Execute: semaphore2                                                    =
//=-------------------------------------------------------------------------=
//=  Author: Ken Christensen                                                =
//=          University of South Florida                                    =
//=          WWW: http://www.csee.usf.edu/~christen                         =
//=          Email: christen@csee.usf.edu                                   =
//=-------------------------------------------------------------------------=
//=  History: KJC (02/27/11) - Genesis (from semaphore1.c)                  =
//==========================================================================
//----- Include files -------------------------------------------------------
#include <stdio.h>                // Needed for printf()
#include <windows.h>              // Needed for windows stuff

//----- Defines -------------------------------------------------------------
#define    TRUE      1            // Boolean true
#define   FALSE      0            // Boolean false
#define    T_ON   2000            // Time to be on (milliseconds)
#define    T_OFF  5000            // Time to be off (milliseconds

//----- Globals -------------------------------------------------------------
HANDLE GhSemaphore;               // Windows semaphore
int    OnFlag;                    // On period flag

//----- Function prototypes -------------------------------------------------
DWORD WINAPI printThread(LPVOID);    // Thread to print
DWORD WINAPI timingThread(LPVOID);   // Thread to periodically pause print

//===========================================================================
//=  Main program                                                           =
//===========================================================================
int main(void)
{
  HANDLE aThread;      // Thread handle a
  HANDLE bThread;      // Thread handle b
  DWORD ThreadID;      // Thread ID

  // Create a semaphore with initial count of 0 and max count of 1
  GhSemaphore = CreateSemaphore(NULL, 0, 1, NULL);
  if (GhSemaphore == NULL)
  {
    printf("*** ERROR - CreateSemaphore() failed \n");
    exit(1);
  }

  // Create the timing thread
  aThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) timingThread, NULL, 0, &ThreadID);
  if(aThread == NULL)
  {
    printf("*** ERROR - CreateThread() failed \n");
    exit(1);
  }

  // Sleep for 1 millisecond to allow timingThread to start
  Sleep(1);

  // Create the print thread
  bThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) printThread, NULL, 0, &ThreadID);
  if(bThread == NULL)
  {
    printf("*** ERROR - CreateThread() failed \n");
    exit(1);
  }

  // Sleep for 30 seconds while threads run
  Sleep(30000);

  // Close thread and semaphore handles
  CloseHandle(aThread);
  CloseHandle(bThread);
  CloseHandle(GhSemaphore);

  // Return
  return(0);
}

//===========================================================================
//=  This is is the timing thread function                                  =
//===========================================================================
DWORD WINAPI timingThread(LPVOID lpParam)
{
  while(1)
  {
    // Sleep for T_ON milliseconds for the ON period
    OnFlag = TRUE;
    Sleep(T_ON);

    // Sleep for T_OFF milliseconds for the OFF period
    OnFlag = FALSE;
    Sleep(T_OFF);

    // Release the semaphore for the next ON period
    ReleaseSemaphore(GhSemaphore, 1, NULL);
  }
}

//===========================================================================
//=  This is is the print thread function                                   =
//===========================================================================
DWORD WINAPI printThread(LPVOID lpParam)
{
  int index;          // Index for print loop

  // Loop forever
  index = 0;
  while(1)
  {
    // Code to print if ON else pause for T_OFF
    if (OnFlag == TRUE)
    {
      index++;
      printf("%2d ", index);
      Sleep(101);
    }
    else
    {
      WaitForSingleObject(GhSemaphore, INFINITE);
      printf("\n");
    }
  }
}

