Example (__lxchg -- Exchange Integer Value with Memory)

This example creates five separate threads, each associated with a state. At most two threads can have a State of Eating at the same time. When a thread calls PickUpChopSticks, that function checks the states of the preceding threads to make sure they are not already Eating. If the call to __lxchg is successful, the thread has locked the Lock semaphore and can change its State to Eating. It then calls __lxchg a second time to unlock the semaphore, and returns.

If __lxchg cannot lock the semaphore, that means another thread has it locked. The current thread then suspends itself briefly with:

OS/2 DosSleep
Windows Sleep

and tries again. The semaphore is used to ensure that two threads cannot simultaneously change their State to Eating, which would cause a deadlock. (Although the semaphore solves the problem of deadlock, it is not an optimal solution; some threads may never get the semaphore or the State of Eating.)

Note: You must compile this example with the multithread (/Gm) option. The example runs in an infinite loop; press Ctrl-C to end it.

   #pragma strings(readonly)
#if  (1 == __TOS_OS2__)
      #define   INCL_DOS                              /* For OS/2 */
      #include <os2.h>
      #define SLEEP  DosSleep(1)
#else
     #include <windows.h>                          /* For Windows */
     #define SLEEP  Sleep(1)
#endif
   #include <stdlib.h>
   #include <stdio.h>
   #include <builtin.h>
   typedef enum {
      Thinking,
      Eating,
      Hungry
   } States;
   #define UNLOCKED 0
   #define LOCKED   1
   #define NUM_PHILOSOPHERS 5
   static volatile int Lock;
   static States State[NUM_PHILOSOPHERS];
   static const int NameMap[NUM_PHILOSOPHERS] = {0, 1, 2, 3, 4};
   static const char * const Names[NUM_PHILOSOPHERS] = {"Plato",
                                                        "Socrates",
                                                        "Kant",
                                                        "Hegel",
                                                        "Nietsche"};
   void PickUpChopSticks(int Ident);
   void PutDownChopSticks(int Ident);
   void Think(int Ident);
   void Eat(int Ident);
   void _Optlink StartPhilosopher(void *pIdent);
   void _Optlink StartPhilosopher(void *pIdent)
   {
      int Ident = *(int *)pIdent;
      while (1) {
         State[Ident] = Hungry;
         printf("%s hungry.\n", Names[Ident]);
         PickUpChopSticks(Ident);
         Eat(Ident);
         PutDownChopSticks(Ident);
         Think(Ident);
      }
   }
   int main(int argc, char *argv[], char *envp[])
   {
      int           i;
      unsigned long tid;
      for (i = 0; i < NUM_PHILOSOPHERS; i++) {
         tid = _beginthread(StartPhilosopher, NULL, 8192, (void *)&NameMap[i]);
         if (tid == -1) {
            printf("Unable to start %s.\n", Names[i]);
         }
         else {
            printf("%s started with Thread Id = %d.\n", Names[i], tid);
         }
      }
#if  (1 == __TOS_OS2__)
      DosWaitThread(&tid, DCWW_WAIT);
#else
      WaitForSingleObject((HANDLE)tid, INFINITE);
#endif
      return 0;
   }
   void PickUpChopSticks(int Ident)
   {
      while (1) {
         if (State[(Ident + NUM_PHILOSOPHERS - 1) % NUM_PHILOSOPHERS] != Eating &&
             State[(Ident + 1) % NUM_PHILOSOPHERS] != Eating                    &&
             !__lxchg(&Lock, LOCKED)) {
               State[Ident] = Eating;
               __lxchg(&Lock, UNLOCKED);
               return;
         }
         else {
            SLEEP;
         }
      }
   }
   void PutDownChopSticks(int Ident)
   {
      State[Ident] = Thinking;
   }
   void Eat(int Ident)
   {
      printf("%s eating.\n", Names[Ident]);
      SLEEP;
   }
   void Think(int Ident)
   {
      printf("%s thinking.\n", Names[Ident]);
      SLEEP;   
   /****************************************************************************
      The output should be similar to :
      Plato started with Thread Id = 2.
      Socrates started with Thread Id = 3.
      Kant started with Thread Id = 4.
      Hegel started with Thread Id = 5.
      Nietsche started with Thread Id = 6.
      Plato hungry.
      Plato eating.
      Socrates hungry.
      Kant hungry.
      Kant eating.
      Hegel hungry.
      Nietsche hungry.
      Kant thinking.
      Plato thinking.
      Plato hungry.
      Plato eating.
      Kant hungry.
      Kant eating.
         :
   ****************************************************************************/
}