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:
| DosSleep | |
| 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.
:
****************************************************************************/ }