#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include "pth.h"
#include "test_common.h"
#define PHILNUM 5
typedef enum {
thinking,
hungry,
eating
} philstat;
static const char *philstatstr[3] = {
"thinking",
"hungry ",
"EATING "
};
typedef struct tablestruct {
pth_t tid[PHILNUM];
int self[PHILNUM];
pth_mutex_t mutex;
pth_cond_t condition[PHILNUM];
philstat status[PHILNUM];
} table;
static table *tab;
static void printstate(void)
{
int i;
for (i = 0; i < PHILNUM; i++)
printf("| %s ", philstatstr[(int)(tab->status)[i]]);
printf("|\n");
return;
}
static int test(unsigned int i)
{
if ( ((tab->status)[i] == hungry)
&& ((tab->status)[(i + 1) % PHILNUM] != eating)
&& ((tab->status)[(i - 1 + PHILNUM) % PHILNUM] != eating)) {
(tab->status)[i] = eating;
pth_cond_notify(&((tab->condition)[i]), FALSE);
return TRUE;
}
return FALSE;
}
static void pickup(unsigned int k)
{
pth_mutex_acquire(&(tab->mutex), FALSE, NULL);
(tab->status)[k] = hungry;
printstate();
if (!test(k))
pth_cond_await(&((tab->condition)[k]), &(tab->mutex), NULL);
printstate();
pth_mutex_release(&(tab->mutex));
return;
}
static void putdown(unsigned int k)
{
pth_mutex_acquire(&(tab->mutex), FALSE, NULL);
(tab->status)[k] = thinking;
printstate();
test((k + 1) % PHILNUM);
test((k - 1 + PHILNUM) % PHILNUM);
pth_mutex_release(&(tab->mutex));
return;
}
static void *philosopher(void *_who)
{
unsigned int *who = (unsigned int *)_who;
for (;;) {
pth_sleep((*who) + 1);
pickup((*who));
pth_sleep(1);
putdown((*who));
}
return NULL;
}
int main(int argc, char *argv[])
{
int i;
sigset_t ss;
int sig;
pth_event_t ev;
pth_init();
printf("This is TEST_PHILO, a Pth test showing the Five Dining Philosophers\n");
printf("\n");
printf("This is a demonstration showing the famous concurrency problem of the\n");
printf("Five Dining Philosophers as analysed 1965 by E.W.Dijkstra:\n");
printf("\n");
printf("Five philosophers are sitting around a round table, each with a bowl of\n");
printf("Chinese food in front of him. Between periods of talking they may start\n");
printf("eating whenever they want to, with their bowls being filled frequently.\n");
printf("But there are only five chopsticks available, one each to the left of\n");
printf("each bowl - and for eating Chinese food one needs two chopsticks. When\n");
printf("a philosopher wants to start eating, he must pick up the chopstick to\n");
printf("the left of his bowl and the chopstick to the right of his bowl. He\n");
printf("may find, however, that either one (or even both) of the chopsticks is\n");
printf("unavailable as it is being used by another philosopher sitting on his\n");
printf("right or left, so he has to wait.\n");
printf("\n");
printf("This situation shows classical contention under concurrency (the\n");
printf("philosophers want to grab the chopsticks) and the possibility of a\n");
printf("deadlock (all philosophers wait that the chopstick to their left becomes\n");
printf("available).\n");
printf("\n");
printf("The demonstration runs max. 60 seconds. To stop before, press CTRL-C.\n");
printf("\n");
printf("+----P1----+----P2----+----P3----+----P4----+----P5----+\n");
tab = (table *)malloc(sizeof(table));
if (!pth_mutex_init(&(tab->mutex))) {
perror("pth_mutex_init");
exit(1);
}
for (i = 0; i < PHILNUM; i++) {
(tab->self)[i] = i;
(tab->status)[i] = thinking;
if (!pth_cond_init(&((tab->condition)[i]))) {
perror("pth_cond_init");
exit(1);
}
}
for (i = 0; i < PHILNUM; i++) {
if (((tab->tid)[i] =
pth_spawn(PTH_ATTR_DEFAULT, philosopher,
&((tab->self)[i]))) == NULL) {
perror("pth_spawn");
exit(1);
}
}
sigemptyset(&ss);
sigaddset(&ss, SIGINT);
ev = pth_event(PTH_EVENT_TIME, pth_timeout(60,0));
pth_sigwait_ev(&ss, &sig, ev);
pth_event_free(ev, PTH_FREE_ALL);
for (i = 0; i < PHILNUM; i++)
pth_cancel((tab->tid)[i]);
while (pth_join(NULL, NULL));
printf("+----------+----------+----------+----------+----------+\n");
free(tab);
pth_kill();
return 0;
}