home *** CD-ROM | disk | FTP | other *** search
/ The Developer Connection…ice Driver Kit for OS/2 3 / DEV3-D1.ISO / devtools / os2tk21j / c / samples / semaph / semaph.c__ / semaph.c
Encoding:
C/C++ Source or Header  |  1993-03-12  |  26.4 KB  |  622 lines

  1. /*static char *SCCSID = "@(#)semaph.c    6.12 92/02/19";*/
  2. /*==============================================================*\
  3.  *  SEMAPH.C - routines for demonstrating semaphore API.        *
  4.  *        (C) Copyright IBM Corporation 1992.                   *
  5.  *--------------------------------------------------------------*
  6.  *  This module contains code to demonstrate the use of         *
  7.  *  semaphores to control access to a resource shared by        *
  8.  *  multiple threads. Event semaphores are used to signal a     *
  9.  *  thread is to give up a resource. A Mutex semaphore is used  *
  10.  *  to provide exclusive access to the resource. A mux          *
  11.  *  semaphore provides a method to check multiple event         *
  12.  *  semaphores.                                                 *
  13.  *                                                              *
  14.  *                                                              *
  15.  *--------------------------------------------------------------*
  16.  *                                                              *
  17.  *  This source file contains the following functions:          *
  18.  *                                                              *
  19.  *        VOID   SemError(PSZ,ULONG);                           *
  20.  *        ULONG  CreateAllSems(VOID);                           *
  21.  *        VOID   StartSemExample(VOID);                         *
  22.  *        VOID   ThreadConsumer(ULONG);                         *
  23.  *        VOID   SignalUserEvent(PULONG pfAutoMode);            *
  24.  *        ULONG  SetAutoMode(VOID);                             *
  25.  *        VOID   RunAuto(VOID);                                 *
  26.  *        VOID   StopSemaphore(VOID);                           *
  27.  *                                                              *
  28.  *                                                              *
  29. \*==============================================================*/
  30.  
  31. /*--------------------------------------------------------------*\
  32.  *  Include files, macros, defined constants, and externs       *
  33. \*--------------------------------------------------------------*/
  34. #include "semaph.h"
  35.  
  36. /*--------------------------------------------------------------*\
  37.  *  Global variables                                            *
  38. \*--------------------------------------------------------------*/
  39. extern LONG colors[MAXUSERS];
  40. extern LONG clrText[MAXUSERS];
  41. static VOID MyMove (ULONG usMyID, ULONG ulUser);
  42.  
  43. /****************************************************************\
  44.  * Procedure to print error messages to screen in a Message Box.*
  45.  *--------------------------------------------------------------*
  46.  *                                                              *
  47.  *  Name:    SemError(pszAPIName,usErrorCode)                   *
  48.  *                                                              *
  49.  *  Purpose: Used to print name of API and error number when    *
  50.  *           a return code other than 0 is returned from an     *
  51.  *           API call.                                          *
  52.  *                                                              *
  53.  *  Usage:   Called by all procedures in this file whenever     *
  54.  *           an API call fails.                                 *
  55.  *                                                              *
  56.  *  Method:  The error number is converted to a string.  String *
  57.  *           functions are used to build the error message.     *
  58.  *           The message is printed in a Message Box.           *
  59.  *                                                              *
  60.  *  NOTE:    This function is called by multiple threads,       *
  61.  *           therefore, only re-entrant functions can be used.  *
  62.  *           Note that string is build according to American    *
  63.  *           English conventions using hard-coded strings, and  *
  64.  *           so portability to other languages would require a  *
  65.  *           more flexible approach.                            *
  66.  *                                                              *
  67.  *  Returns: none.                                              *
  68.  *                                                              *
  69. \****************************************************************/
  70. VOID SemError(PSZ pszAPIName,ULONG usErrorCode)
  71. {
  72.    char acMessage[100],acErrorNumber[10];
  73.  
  74.    _itoa(usErrorCode,acErrorNumber,BASETEN);
  75.    strcpy(acMessage,pszAPIName);
  76.    strcat(acMessage,": error # ");
  77.    strcat(acMessage,acErrorNumber);
  78.  
  79.    WinMessageBox(HWND_DESKTOP,
  80.                  hwndMain,
  81.                  acMessage,
  82.                  szAppName,
  83.                  1,
  84.                  MB_OK);
  85.    return;
  86. }
  87.  
  88. /****************************************************************\
  89.  * Routine to create  semaphores used in this file.             *
  90.  *--------------------------------------------------------------*
  91.  *                                                              *
  92.  *  Name:    CreateAllSems(VOID)                                *
  93.  *                                                              *
  94.  *  Purpose: Create semaphores needed by the consumer threads.  *
  95.  *           Checks return codes from semaphore creation.       *
  96.  *                                                              *
  97.  *  Usage:   Called by StartSemExample.                         *
  98.  *                                                              *
  99.  *  Method:  Semaphores are all anonymous private semaphores    *
  100.  *           since the semaphores are used by threads in the    *
  101.  *           same process.                                      *
  102.  *                                                              *
  103.  *  Returns: 0 if all semaphores are created successfully.      *
  104.  *           Otherwise returns error code for first create      *
  105.  *           semaphore API to fail.                             *
  106.  *                                                              *
  107. \****************************************************************/
  108. ULONG CreateAllSems(VOID)
  109. {
  110.    ULONG      rc;
  111.    SEMRECORD   asr[MAXRESOURCES];
  112.    INT         i;
  113.  
  114.    rc = DosCreateMutexSem((PSZ)NULL,&hmtxOwnResource, 0L,FALSE);
  115.    if (rc)
  116.    {
  117.        SemError("DosCreateMutexSem",rc);
  118.        return(rc);
  119.    }
  120.  
  121.    for (i = 0; i < MAXRESOURCES; i++)
  122.    {
  123.       rc = DosCreateEventSem( (PSZ)NULL, &aSquares[i].hev,
  124.                                       0L, FALSE);
  125.       if (rc)
  126.       {
  127.           SemError("DosCreateEventSem",rc);
  128.           return(rc);
  129.       }
  130.       else
  131.       {
  132.           asr[i].ulUser = i;
  133.           asr[i].hsemCur = (PVOID) aSquares[i].hev;
  134.       }
  135.    }
  136.                           /* this muxwait semaphore contains all of the
  137.                           event semaphores created in the loop above. */
  138.    rc = DosCreateMuxWaitSem((PSZ)NULL,&hmuxResource,
  139.            MAXRESOURCES,asr, DCMW_WAIT_ANY);
  140.    if (rc)
  141.    {
  142.       SemError("DosCreateMuxWaitSem",rc);
  143.       return(rc);
  144.    }
  145.    rc = DosCreateEventSem((PSZ)NULL,&hevStop,0L,FALSE);
  146.    if (rc)
  147.    {
  148.        SemError("DosCreateEventSem",rc);
  149.        return(rc);
  150.    }
  151.    return(rc);
  152. }
  153.  
  154. /****************************************************************\
  155.  * Routine to start semaphore example                           *
  156.  *--------------------------------------------------------------*
  157.  *                                                              *
  158.  *  Name:     StartSemExample(VOID)                             *
  159.  *                                                              *
  160.  *  Purpose:  Calls routines to create semaphores and draw      *
  161.  *            resources.  Creates consumer threads.             *
  162.  *                                                              *
  163.  *  Usage:    Called in file usercmd.c when the user selects    *
  164.  *            start from the semaphore menu.                    *
  165.  *                                                              *
  166.  *  Method:   Uses routines in paint.c to draw consumers and    *
  167.  *            resources.  This is done by creating a paint      *
  168.  *            message, not calling the draw routines directly.  *
  169.  *                                                              *
  170.  *  Returns:  TRUE if start succeeds, FALSE if start fails      *
  171.  *                                                              *
  172. \****************************************************************/
  173. INT   StartSemExample(VOID)
  174. {
  175.     TID         tid=0;
  176.     ULONG       rc;
  177.     INT         i;
  178.     FONTMETRICS fntmet;
  179.     HPS         hps;
  180.     SWP         swp;
  181.  
  182.     InitSemaphExample();
  183.  
  184.     rc = CreateAllSems();
  185.  
  186.     if (rc)
  187.         return FALSE;
  188.     /****************************************************************\
  189.      * Create consumer threads. Note that values can be passed to   *
  190.      * threads in OS/2 2.0. We pass the ordinal number of the child *
  191.      * to each child.                                               *
  192.     \****************************************************************/
  193.  
  194.     for (usConsumerThreadsCreated = 0;
  195.      usConsumerThreadsCreated < cNumUsers; usConsumerThreadsCreated++)
  196.     {
  197.         rc = DosCreateThread((PTID) &tid, (PFNTHREAD)ThreadConsumer,
  198.              (ULONG) usConsumerThreadsCreated, (ULONG)1,(ULONG) STACKSIZE);
  199.         if (rc)
  200.         {
  201.             SemError("DosCreateThread",rc);
  202.             return FALSE;
  203.         }
  204.         else
  205.         {
  206.             thrConsumers[usConsumerThreadsCreated].tid = tid;
  207.             thrConsumers[usConsumerThreadsCreated].lHits = 0L;
  208.         }
  209.     }
  210.     for (i = 0; i < (INT) cNumUsers; i++)
  211.     {
  212.         DosResumeThread (thrConsumers[i].tid);
  213.     }
  214.     hps = WinGetPS (hwndMain);
  215.     if (hps)
  216.     {
  217.         GpiQueryFontMetrics (hps, (LONG) sizeof fntmet, &fntmet);
  218.         WinQueryWindowPos (hwndMain, &swp);
  219.         SetRectPositions((SHORT)swp.cx, (SHORT)swp.cy,
  220.                          (SHORT) fntmet.lMaxBaselineExt,
  221.                          (SHORT) fntmet.lMaxDescender);
  222.         DrawRects (hps);
  223.         WinReleasePS (hps);
  224.     }
  225.     return TRUE;
  226. }
  227.  
  228. /****************************************************************\
  229.  * Routine to signal consumer to release resource.              *
  230.  *--------------------------------------------------------------*
  231.  *                                                              *
  232.  *  Name:     SignalUserEvent(pfAutoMode)                       *
  233.  *                                                              *
  234.  *  Purpose:  Posts user event semaphore to signal thread to    *
  235.  *            release resource.  Also posts event to stop       *
  236.  *            Auto mode if *pfAutoMode is true.                 *
  237.  *                                                              *
  238.  *  Usage:    Called in file usercmd.c when the user selects    *
  239.  *            Event from the semaphore menu.                    *
  240.  *                                                              *
  241.  *  Method:   Turns off Auto mode, if present by posting auto   *
  242.  *            semaphore.  User event is then posted.            *
  243.  *                                                              *
  244.  *  Returns:                                                    *
  245.  *                                                              *
  246. \****************************************************************/
  247. VOID SignalUserEvent(PULONG pfAutoMode)
  248. {
  249.   ULONG rc;
  250.  
  251.                           /* If sample is in auto mode turn auto mode off. */
  252.   if (*pfAutoMode)
  253.   {
  254.       rc = DosPostEventSem(hevStopAuto);
  255.       if (rc)
  256.       {
  257.          SemError("DosPostEventSem Stop Auto",rc);
  258.       }
  259.                        /* Wait for auto mode thread to die, so we don't
  260.                           end up with multiple copies of it later.    */
  261.  
  262.       rc = DosWaitThread(&tidAutoThread,0L);
  263.       if (rc)
  264.       {
  265.          SemError("DosWaitThread",rc);
  266.       }
  267.       *pfAutoMode = FALSE;
  268.       DosCloseEventSem (hevStopAuto);
  269.   }
  270.  
  271.   /* If Auto mode haas already posted the event this is OK
  272.      so we will not check error codes here. */
  273.  
  274.   DosPostEventSem(aSquares[rand() % MAXRESOURCES].hev);
  275.   return;
  276. }
  277.  
  278. /****************************************************************\
  279.  * Routine to start Auto mode.                                  *
  280.  *--------------------------------------------------------------*
  281.  *                                                              *
  282.  *  Name:     SetAutoMode(VOID)                                 *
  283.  *                                                              *
  284.  *  Purpose:  Creates thread and semaphore needed to run auto   *
  285.  *            mode.                                             *
  286.  *                                                              *
  287.  *  Usage:    Called in file usercmd.c when the user selects    *
  288.  *            Auto from the semaphore menu.                     *
  289.  *                                                              *
  290.  *  Returns:  NO_ERROR on success, else error from api call.    *
  291.  *                                                              *
  292. \****************************************************************/
  293. ULONG SetAutoMode()
  294. {
  295.     ULONG rc;
  296.  
  297.     rc = DosCreateEventSem((PSZ)NULL,&hevStopAuto,0L,FALSE);
  298.     if (rc)
  299.     {
  300.         SemError("DosCreateEventSem",rc);
  301.         return(rc);
  302.     }
  303.  
  304.     rc = DosCreateThread((PTID)&tidAutoThread,(PFNTHREAD)RunAuto,0L,0L,STACKSIZE);
  305.     if (rc)
  306.     {
  307.         DosCloseEventSem (hevStopAuto); /* close semaphore created above */
  308.         SemError("DosCreateThread", rc);
  309.         return(rc);
  310.     }
  311.  
  312.     return(NO_ERROR);
  313. }
  314.  
  315. /****************************************************************\
  316.  * Routine to run Auto mode.                                    *
  317.  *--------------------------------------------------------------*
  318.  *                                                              *
  319.  *  Name:     RunAuto(ULONG ulArg)                              *
  320.  *                                                              *
  321.  *  Purpose:  Posts user event at fixed time interval to signal *
  322.  *            consumers to release resource.                    *
  323.  *                                                              *
  324.  *  Usage:    Thread created by SetAutoMode.                    *
  325.  *                                                              *
  326.  *  Method:   Kills itself when StopAutoMode semaphore is       *
  327.  *            posted.                                           *
  328.  *                                                              *
  329.  *  Returns:                                                    *
  330.  *                                                              *
  331. \****************************************************************/
  332. VOID RunAuto( ULONG ulArg )
  333. {
  334.    ULONG rcWait;
  335.    HAB habLocal;
  336.    HMQ hmqLocal;
  337.    INT i;
  338.  
  339.    /* Need a message queue for any thread that wants to print messages. */
  340.  
  341.    habLocal = WinInitialize(0);
  342.    hmqLocal = WinCreateMsgQueue(habLocal,0);
  343.  
  344.    /* while stop auto semaphore not posted, post user event semaphore. */
  345.  
  346.       /***************************************************************
  347.        * Don't check return code from DosPostEventSem(hevUserEvent)  *
  348.        * since we just want the resource to change hands.  We don't  *
  349.        * care if it changes hands exactly every time it goes through *
  350.        * the loop.                                                   *
  351.        *                                                             *
  352.        * The event may already be posted if the system is busy and   *
  353.        * the resource threads don't finish with it fast enough.      *
  354.        * This is not a problem in this case.                         *
  355.        ***************************************************************/
  356.  
  357.    do {                      /* if ulTimeout is zero, still waitevent
  358.                                  for 1 msec to force yielding of CPU. */
  359.        rcWait = DosWaitEventSem(hevStopAuto, max (ulTimeout, 1));
  360.        if (rcWait == ERROR_TIMEOUT)
  361.        {
  362.            i = rand () % MAXRESOURCES;      /* generate it */
  363.            DosPostEventSem (aSquares[i].hev);
  364.        }
  365.    } while (rcWait == ERROR_TIMEOUT);
  366.  
  367.    /* If there was an error, print a message */
  368.  
  369.    if (rcWait)
  370.    {
  371.       SemError("DosWaitEventSem",rcWait);
  372.    }
  373.  
  374.    WinDestroyMsgQueue (hmqLocal);
  375.    WinTerminate (habLocal);
  376.    DosExit(EXIT_THREAD,0);
  377.  
  378.                 /* Since ulArg is not referenced anywhere we must use this
  379.                    use this dummy reference to stop a compiler warning.    */
  380.    ++ulArg;
  381.    return;
  382. }
  383.  
  384. /****************************************************************\
  385.  * Routine to stop semaphore example.                           *
  386.  *--------------------------------------------------------------*
  387.  *                                                              *
  388.  *  Name:     BeginStop(pfAutoMode)                             *
  389.  *                                                              *
  390.  *  Purpose:  Posts stop event semaphore to signal threads to   *
  391.  *            die.  Also posts event to stop Auto mode if       *
  392.  *            necessary. Then waits for threads to complete,    *
  393.  *            Creates thread StopSemaphore which posts stop     *
  394.  *            event and waits for child threads.                *
  395.  *                                                              *
  396.  *  Usage:    Called in file usercmd.c when the user selects    *
  397.  *            Stop from the semaphore menu.                     *
  398.  *                                                              *
  399.  *  Method:   Execs thread to do waits so that message thread   *
  400.  *            doesn't hang.                                     *
  401.  *  Returns:                                                    *
  402.  *                                                              *
  403. \****************************************************************/
  404. VOID BeginStop (PULONG pfAutoMode)
  405. {
  406.    ULONG rc;
  407.    TID tidLocal;
  408.  
  409.    rc = DosPostEventSem(hevStop);
  410.    if (rc)
  411.    {
  412.        SemError("DosPostEventSem",rc);
  413.        return;
  414.    }
  415.    if (*pfAutoMode)
  416.    {
  417.        rc = DosPostEventSem(hevStopAuto);
  418.        if (rc)
  419.        {
  420.           SemError("DosPostEventSem",rc);
  421.        }
  422.    }
  423.    rc = DosCreateThread((PTID)&tidLocal, (PFNTHREAD)StopSemaphore,
  424.                           (ULONG)pfAutoMode,(ULONG)0,(ULONG) STACKSIZE);
  425.    if (rc)
  426.    {
  427.        SemError("DosCreateThread",rc);
  428.    }
  429.    return;
  430. }
  431.  
  432. /****************************************************************\
  433.  * Routine to really stop semaphore example.                    *
  434.  *--------------------------------------------------------------*
  435.  *                                                              *
  436.  *  Name:     StopSemaphore( ULONG ulArg )                      *
  437.  *                                                              *
  438.  *  Purpose:  Waits for threads to complete,                    *
  439.  *            Sends message to message thread to indicate this  *
  440.  *            has occurred, and exits.                          *
  441.  *                                                              *
  442.  *  Usage:    Exec'd from BeginStop when user selects Stop from *
  443.  *            Semaphore menu.                                   *
  444.  *                                                              *
  445.  *  Method:   Turns off Auto mode, if present by posting auto   *
  446.  *            semaphore.  Then stop event is posted.  Waits     *
  447.  *            for threads to die.                               *
  448.  *  Returns:                                                    *
  449.  *                                                              *
  450. \****************************************************************/
  451. VOID StopSemaphore( ULONG ulArg )
  452. {
  453.    ULONG rc,usCount, i;
  454.    PULONG pfAutoMode = (PULONG)ulArg;
  455.  
  456.    if (*pfAutoMode)
  457.    {
  458.       rc = DosWaitThread(&tidAutoThread,0L);
  459.       if (rc && (rc != ERROR_INVALID_THREADID))
  460.       {
  461.          SemError("DosWaitThread",rc);
  462.       }
  463.       *pfAutoMode = FALSE;
  464.    }
  465.    /* Wait for usConsumer threads to die.  Order of death not important. */
  466.  
  467.    for (usCount = 0; usCount < usConsumerThreadsCreated; usCount++)
  468.    {
  469.       rc = DosWaitThread(&thrConsumers[usCount].tid,0L);
  470.  
  471.       /* rc is ERROR_INVALID_THREADID the thread is already dead.*\
  472.       \* This is OK and not a error.                             */
  473.  
  474.       if (rc && (rc != ERROR_INVALID_THREADID))
  475.       {
  476.          SemError("DosWaitThread",rc);
  477.       }
  478.    }
  479.                 /* Threads dead so we don't need semaphores any more.  */
  480.    DosCloseEventSem(hevStopAuto);
  481.    DosCloseEventSem(hevStop);
  482.    DosCloseMutexSem(hmtxOwnResource);
  483.    for (i = 0; i < MAXRESOURCES; i++)
  484.    {
  485.       DosCloseEventSem(aSquares[i].hev);
  486.    }
  487.    DosCloseMuxWaitSem (hmuxResource);
  488.    WinPostMsg (hwndMain, WM_COMMAND, (MPARAM)IDM_STOPFINISHED, (MPARAM)NULL);
  489.    DosExit (EXIT_THREAD, 0);
  490.    return;
  491. }
  492.  
  493. /****************************************************************\
  494.  * Routine for consumer threads.                                *
  495.  *--------------------------------------------------------------*
  496.  *                                                              *
  497.  *  Name:     ThreadConsumer(ULONG)                             *
  498.  *                                                              *
  499.  *  Purpose:  There are NUMUSERS copies of this thread to act   *
  500.  *            as consumers of the resource. The thread waits for*
  501.  *            exclusive access to the resource and colors it.   *
  502.  *                                                              *
  503.  *  Usage:    Threads created by StartSemExample.               *
  504.  *                                                              *
  505.  *  Method:   Waits for mutex to gain ownership of resource.    *
  506.  *            Releases resource when user event. Dies when      *
  507.  *            Stop event.                                       *
  508.  *  Returns:                                                    *
  509.  *                                                              *
  510. \****************************************************************/
  511. VOID ThreadConsumer( ULONG ulMyID )
  512. {
  513.    ULONG  ulPostCnt;
  514.    ULONG  ulUser=0L;
  515.    ULONG  rc;
  516.    HAB    habb;
  517.    HMQ    hmqq;
  518.  
  519.    /* Need a message queue for any thread that wants to print messages. */
  520.    habb = WinInitialize(0);
  521.    hmqq = WinCreateMsgQueue(habb,0);
  522.  
  523.    /* while the user has not selected stop ... */
  524.    while ((DosWaitEventSem(hevStop,SEM_IMMEDIATE_RETURN)) == ERROR_TIMEOUT)
  525.    {
  526.       /* Wait for exclusive ownership of resource */
  527.  
  528.       DosRequestMutexSem(hmtxOwnResource,SEM_INDEFINITE_WAIT);
  529.  
  530.       /* the following check is necessary because the stop semaphore
  531.        * may have been posted  while we were waiting on the mutex
  532.        */
  533.       if (DosWaitEventSem(hevStop, SEM_IMMEDIATE_RETURN) == ERROR_TIMEOUT)
  534.       {
  535.       /*********************************************************************\
  536.        * an item is ready, which one?  don't wait forever because there is *
  537.        * a possibility that the stop semaphore was posted and that no more *
  538.        * resource is forthcoming. we wait twice as long as we think is     *
  539.        * necessary.                                                        *
  540.       \*********************************************************************/
  541.          if (!DosWaitMuxWaitSem (hmuxResource, max (ulTimeout << 1,
  542.             TIMEOUTPERIOD) , &ulUser))
  543.          {
  544.             MyMove (ulMyID, ulUser);
  545.             DosResetEventSem(aSquares[ulUser].hev, &ulPostCnt);
  546.          }
  547.       }
  548.                                /* Let some other thread have resource. */
  549.       rc = DosReleaseMutexSem(hmtxOwnResource);
  550.       if (rc)
  551.       {
  552.          SemError("DosReleaseMutexSem",rc);
  553.       }
  554.    }
  555.    /* hevStop was posted, kill this thread */
  556.    WinDestroyMsgQueue (hmqq);
  557.    WinTerminate (habb);
  558.    DosExit(EXIT_THREAD, 0);
  559.    return;
  560. }
  561.  
  562. /****************************************************************\
  563.  *  called from ThreadConsumer to make and register move        *
  564.  *--------------------------------------------------------------*
  565.  *                                                              *
  566.  *  Name: MyMove (usMyID, ulUser)                               *
  567.  *        ULONG     usMyID;     id of caller                    *
  568.  *        ULONG     ulUser;     number of the square to "hit"   *
  569.  *                                                              *
  570.  *  Purpose: color a square on the game board 'my' color.       *
  571.  *           update display of number of hits for 'my' thread.  *
  572.  *                                                              *
  573.  *  Usage: called only from ThreadConsumer                      *
  574.  *                                                              *
  575.  *  Method:                                                     *
  576.  *                                                              *
  577.  *  Returns: none                                               *
  578.  *                                                              *
  579. \****************************************************************/
  580. static VOID MyMove (ULONG usMyID, ULONG ulUser)
  581. {
  582.    if (aSquares [ulUser].usOwner != usMyID)
  583.    {
  584.       aSquares[ulUser].usOwner = usMyID;
  585.       thrConsumers[usMyID].lHits++;
  586.       DrawResource (&aSquares[ulUser].rcl, colors [usMyID]);
  587.       DrawStats (usMyID);
  588.    }
  589.    return;
  590. }
  591.  
  592. /****************************************************************\
  593.  * Routine to init game board                                   *
  594.  *--------------------------------------------------------------*
  595.  *                                                              *
  596.  *  Name:     InitSemaphExample(VOID)                           *
  597.  *                                                              *
  598.  *  Purpose:  Initializes game board unowned, sets semaphores   *
  599.  *            to 0.                                             *
  600.  *  Usage:    Called from StartSemExample in semaph.c when      *
  601.  *            user selects start from the semaphore menu.       *
  602.  *  Method:                                                     *
  603.  *                                                              *
  604.  *  Returns:  none                                              *
  605.  *                                                              *
  606. \****************************************************************/
  607. VOID InitSemaphExample(VOID)
  608. {
  609.    int i;
  610.  
  611.    for (i = 0; i < MAXRESOURCES; i++)
  612.    {
  613.       aSquares[i].hev = 0;
  614.       aSquares[i].usOwner = UNOWNED;
  615.    }
  616.    hevStopAuto = 0L;
  617.    hevStop = 0L;
  618.    hmtxOwnResource = 0L;
  619.    hmuxResource  = 0L;
  620.    return;
  621. }
  622.