v02i085: phil -- Example of the "Dining Philosophers" problem (System V)
Jim Pickering
jrp at rducky.UUCP
Sun Apr 3 16:18:38 AEST 1988
Submitted-By: "Jim Pickering" <jrp at rducky.UUCP>
Archive-Name: phil
comp.sources.misc: Volume 2, Issue 85
Submitted-By: "Jim Pickering" <jrp at rducky.UUCP>
Archive-Name: phil
[An example of the "dining philosophers" problem in process synchronization,
implemented via System V semaphores. Should be educational both with regard
to process synchronization and to semaphore usage. ++bsa]
#--------------------------------CUT HERE-------------------------------------
#! /bin/sh
#
# This is a shell archive. Save this into a file, edit it
# and delete all lines above this comment. Then give this
# file to sh by executing the command "sh file". The files
# will be extracted into the current directory owned by
# you with default permissions.
#
# The files contained herein are:
#
# -rw-r--r-- 1 jrp users 27897 Apr 2 15:14 phil.c
#
echo 'x - phil.c'
if test -f phil.c; then echo 'shar: not overwriting phil.c'; else
sed 's/^X//' << '________This_Is_The_END________' > phil.c
X/***********************************************************************/
X/** PHIL.C **/
X/** **/
X/** (c) COPYRIGHT 1988 **/
X/** JAMES R. PICKERING **/
X/** ALL RIGHTS RESERVED **/
X/** **/
X/** Jim Pickering || (n) ..csustan!polyslo!rducky!jrp **/
X/** || (s) ..sdsu!polyslo!rducky!jrp **/
X/** Arroyo Grande, CA 93420 || jrp at rducky.UUCP **/
X/** (805) 473-1037 **/
X/** **/
X/** DESCRIPTION: This file contains a program which demonstrates **/
X/** Dijkstra's Dining Philosophers Problem (see "Cooperating **/
X/** Sequential Processes," Technical Report EWD-123, Technological **/
X/** University, Eindhoven, The Netherlands, (1965)). It is con- **/
X/** sidered a classic process synchronization problem. It is **/
X/** implemented using SVR2 semaphores and curses. With this as an **/
X/** example, you may be able to figure out how to use SV semaphores.**/
X/** **/
X/** PROBLEM DESCRIPTION: Five philosophers spend their lives **/
X/** thinking and eating. They share a common table. Each has his/ **/
X/** her own chair. At the center of the table is a bowl of rice. **/
X/** The table is laid with five chopsticks (see figure below). When**/
X/** a philosopher thinks, he/she (the hell with this he/she crap ...**/
X/** all philosophers referenced furthur are hermaphrodites and will **/
X/** be refered to as 'he') does not eat, and vice versa. When a **/
X/** philosopher is hungry he tries to pick up the two chopsticks **/
X/** that are closest to him. He may only pick up one stick at a **/
X/** time. When he has both chopsticks, he eats without releasing **/
X/** his chopsticks. When he is finished eating, he puts down both **/
X/** chopsticks and starts thinking. **/
X/** **/
X/** PHIL1 | PHIL2 **/
X/** \ / **/
X/** **/
X/** PHIL5 (rice) PHIL3 **/
X/** **/
X/** **/
X/** / PHIL4 \ **/
X/** **/
X/** COMPILE: cc -O -s -o phil phil.c -lcurses **/
X/***********************************************************************/
X/** FUNCTIONS: **/
X/** void clean_die() **/
X/** void die() **/
X/** void sleeper() **/
X/** void hungry(p_num) **/
X/** int p_num; **/
X/** void thinking(p_num) **/
X/** int p_num; **/
X/** void eating(p_num) **/
X/** int p_num; **/
X/** void killit(semid,array_ptr) **/
X/** int semid, *array_ptr; **/
X/** void cleanup() **/
X/** void printit(p_num,action) **/
X/** int p_num, action; **/
X/** bool V_semaphore(sem_num) **/
X/** int sem_num; **/
X/** bool P_semaphore(sem_num,block) **/
X/** int sem_num; **/
X/** bool block; **/
X/***********************************************************************/
X
Xstatic char philc[] = "@(#)phil1.c 1.1 JAMES R. PICKERING 3/23/88";
X
X#include <sys/types.h>
X#include <sys/ipc.h>
X#include <sys/sem.h>
X#include <curses.h>
X#include <signal.h>
X#include <errno.h>
X
X#define NUM_CHILDREN 5 /* number of dining philosophers */
X /* don't change this!!!!!!!!!!!! */
X /* the display routines depend on */
X /* this. */
X
X#define SLEEP_TIME 10 /* maximum amount of time (minus 1)
X in seconds the child processes
X eat and think. */
X
X#define EATING 1
X#define THINKING 2
X#define HAS_ONE 3
X#define HUNGRY 4
X
Xvoid die();
Xvoid clean_die();
Xvoid sleeper();
Xvoid hungry();
Xvoid thinking();
Xvoid eating();
Xvoid killit();
Xvoid cleanup();
Xvoid printit();
Xbool V_semaphore();
Xbool P_semaphore();
X
Xint semid; /* the semaphore set id */
Xint pid_array[NUM_CHILDREN]; /* array of children's pids */
X
Xmain()
X{
X
X /************************************************/
X /*variable declarations for semaphore definition*/
X /************************************************/
X
X key_t key;
X int opperm, nsems;
X int opperm_flags;
X
X /****************************************************/
X /*variable declarations for semaphore initialization*/
X /****************************************************/
X
X struct semid_ds semid_ds;
X int i, length;
X int retrn;
X union semnum
X {
X int val;
X struct semid_ds *buf;
X ushort array[25];
X } arg;
X
X
X /*******************************************************/
X /*variable declarations for dining philosophers problem*/
X /*******************************************************/
X
X int p_num;
X
X /***********************************/
X /*get a semaphore set from the O.S.*/
X /***********************************/
X
X key = IPC_PRIVATE;
X opperm = 0600;
X opperm_flags = (opperm | IPC_CREAT | IPC_EXCL);
X nsems = NUM_CHILDREN;
X if((semid = semget(key,nsems,opperm_flags)) == -1)
X {
X perror("The semget call failed with semget(key,nsems,opperm_flags).");
X exit(0);
X }
X
X /************************************************/
X /*initialize the five semaphores in the set to 1*/
X /************************************************/
X
X arg.buf = &semid_ds;
X if ((retrn = semctl(semid,0,IPC_STAT,arg.buf)) == -1)
X {
X perror("The semctl call failed on finding the number of semaphores with semctl(semid,0,IPC_STAT,arg.buf).");
X exit(0);
X }
X length = arg.buf -> sem_nsems;
X for (i=0; i<length; i++)
X arg.array[i] = 1;
X if ((retrn = semctl(semid,0,SETALL,arg.array)) == -1)
X {
X perror("The semctl call failed on initializing the semaphores with semctl(semid,0,SETALL,arg.array).");
X exit(0);
X }
X
X /**********************************************/
X /*fork off five dining philosophers (children)*/
X /**********************************************/
X
X for (i=1; i<=NUM_CHILDREN; i++)
X {
X if ((pid_array[i-1] = fork()) == 0)
X {
X initscr();
X (void)signal(SIGHUP,clean_die);
X (void)signal(SIGQUIT,clean_die);
X (void)signal(SIGINT,clean_die);
X refresh();
X (void)sleep(2);
X srand((unsigned)time((long *)0));
X p_num = i;
X
X /**************************************************************/
X /*philosopher (child) thinks, becomes hungry, eats, thinks ...*/
X /**************************************************************/
X
X while(TRUE)
X {
X thinking(p_num);
X hungry(p_num);
X eating(p_num);
X }
X }
X }
X /****************************/
X /*parent waits for interrupt*/
X /****************************/
X (void)signal(SIGHUP,die);
X (void)signal(SIGINT,die);
X (void)signal(SIGQUIT,die);
X while(TRUE)
X ;
X}
X
X
X/**********************************************************************/
X/**FUNCTION: clean_die() **/
X/** **/
X/**DESCRIPTION: This function calls cleanup (ends curses) and exits.**/
X/** It only is called by the children. **/
X/** **/
X/**GLOBAL VARIABLES: none @ **/
X/** **/
X/**GLOBAL CONSTANTS: none **/
X/** **/
X/**CALLS: cleanup() **/
X/** **/
X/**RETURNS: none **/
X/**********************************************************************/
Xvoid clean_die()
X{
X cleanup();
X exit(0);
X}
X
X
X/**********************************************************************/
X/**FUNCTION: die() **/
X/** **/
X/**DESCRIPTION: This function is called by the parent and sends its **/
X/** children a signal through killit and then exits. **/
X/** **/
X/**GLOBAL VARIABLES: semid, pid_array **/
X/** **/
X/**GLOBAL CONSTANTS: none **/
X/** **/
X/**CALLS: killit() **/
X/** **/
X/**RETURNS: none **/
X/**********************************************************************/
Xvoid die()
X{
X killit(semid,pid_array);
X exit(0);
X}
X
X
X/**********************************************************************/
X/**FUNCTION: sleeper() **/
X/** **/
X/**DESCRIPTION: This function randomly sleeps from 0 to **/
X/** (SLEEP_TIME-1) seconds. **/
X/** **/
X/**GLOBAL VARIABLES: none **/
X/** **/
X/**GLOBAL CONSTANTS: SLEEP_TIME **/
X/** **/
X/**CALLS: none **/
X/** **/
X/**RETURNS: none **/
X/**********************************************************************/
Xvoid sleeper()
X{
X (void)sleep(rand() % SLEEP_TIME);
X}
X
X
X/**********************************************************************/
X/**FUNCTION: hungry() **/
X/** **/
X/**DESCRIPTION: This function is representative of a philosopher **/
X/** being hungry. **/
X/** **/
X/**GLOBAL VARIABLES: none **/
X/** **/
X/**GLOBAL CONSTANTS: HUNGRY **/
X/** **/
X/**CALLS: printit() **/
X/** **/
X/**RETURNS: none **/
X/**********************************************************************/
Xvoid hungry(p_num)
X int p_num;
X{
X printit(p_num,HUNGRY);
X}
X
X
X/**********************************************************************/
X/**FUNCTION: thinking() **/
X/** **/
X/**DESCRIPTION: This function is representative of a philosopher **/
X/** thinking for a random amount of time. **/
X/** **/
X/**GLOBAL VARIABLES: none **/
X/** **/
X/**GLOBAL CONSTANTS: THINKING **/
X/** **/
X/**CALLS: printit(), sleeper(), **/
X/** **/
X/**RETURNS: none **/
X/**********************************************************************/
Xvoid thinking(p_num)
X int p_num;
X{
X printit(p_num,THINKING);
X sleeper();
X}
X
X
X/**********************************************************************/
X/**FUNCTION: eating() **/
X/** **/
X/**DESCRIPTION: This function is representative of a philosopher **/
X/** eating for a random amount of time. **/
X/** **/
X/**GLOBAL VARIABLES: none **/
X/** **/
X/**GLOBAL CONSTANTS: NUM_CHILDREN, EATING, HAS_ONE **/
X/** **/
X/**CALLS: printit(), P_semaphore(), V_semaphore(), sleeper(), **/
X/** **/
X/**RETURNS: none **/
X/**********************************************************************/
Xvoid eating(p_num)
X int p_num;
X{
X int n = NUM_CHILDREN;
X
X if (!(p_num % 2))
X
X /************************************************/
X /*even philosopher--choose right chopstick first*/
X /* to prevent deadlock */
X /************************************************/
X
X {
X
X /******************************/
X /*P(right chopstick) operation*/
X /******************************/
X
X if (!P_semaphore(p_num-1,TRUE))
X {
X exit(0);
X }
X printit(p_num,HAS_ONE);
X
X /*****************************/
X /*P(left chopstick) operation*/
X /*****************************/
X
X if (!P_semaphore(p_num%n,TRUE))
X {
X (void)V_semaphore(p_num-1);
X exit(0);
X }
X
X /***************************************/
X /*philosopher's critical section begins*/
X /***************************************/
X
X printit(p_num,EATING);
X sleeper();
X
X /*************************************/
X /*Philosopher's critical section ends*/
X /*************************************/
X
X
X /******************************/
X /*V(right chopstick) operation*/
X /******************************/
X
X if(!V_semaphore(p_num-1))
X {
X (void)kill(getppid(),SIGHUP);
X exit(0);
X }
X
X /*****************************/
X /*V(left chopstick operation)*/
X /*****************************/
X
X if(!V_semaphore(p_num%n))
X {
X (void)kill(getppid(),SIGHUP);
X exit(0);
X }
X }
X else
X
X /**********************************************/
X /*odd philosopher--choose left chopstick first*/
X /* to prevent deadlock */
X /**********************************************/
X
X {
X
X /*****************************/
X /*P(left chopstick operation)*/
X /*****************************/
X
X if (!P_semaphore(p_num%n,TRUE))
X {
X exit(0);
X }
X printit(p_num,HAS_ONE);
X
X /*****************************/
X /*P(right chopstick operation*/
X /*****************************/
X
X if (!P_semaphore(p_num-1,TRUE))
X {
X (void)V_semaphore(p_num%n);
X exit(0);
X }
X
X /***************************************/
X /*philosopher's critical section begins*/
X /***************************************/
X
X printit(p_num,EATING);
X sleeper();
X
X /*************************************/
X /*philosopher's critical section ends*/
X /*************************************/
X
X
X /*****************************/
X /*V(left chopstick) operation*/
X /*****************************/
X
X if(!V_semaphore(p_num%n))
X {
X (void)kill(getppid(),SIGHUP);
X exit(0);
X }
X
X /*****************************/
X /*V(right chopstick) operation*/
X /*****************************/
X
X if(!V_semaphore(p_num-1))
X {
X (void)kill(getppid(),SIGHUP);
X exit(0);
X }
X }
X}
X
X
X/**********************************************************************/
X/**FUNCTION: killit() **/
X/** **/
X/**DESCRIPTION: This function is used by the parent to kill its **/
X/** children and remove the semaphore set. **/
X/** **/
X/**GLOBAL VARIABLES: none **/
X/** **/
X/**GLOBAL CONSTANTS: NUM_CHILDREN **/
X/** **/
X/**CALLS: none **/
X/** **/
X/**RETURNS: none **/
X/**********************************************************************/
Xvoid killit(semid,array_ptr)
X int semid, *array_ptr;
X{
X int i;
X
X for (i=0; i<NUM_CHILDREN; i++)
X (void)kill(array_ptr[i],SIGHUP);
X (void)semctl(semid,0,IPC_RMID,0);
X}
X
X
X/**********************************************************************/
X/**FUNCTION: cleanup() **/
X/** **/
X/**DESCRIPTION: This function cleans up curses for the children. **/
X/** **/
X/**GLOBAL VARIABLES: none **/
X/** **/
X/**GLOBAL CONSTANTS: none **/
X/** **/
X/**CALLS: none **/
X/** **/
X/**RETURNS: none **/
X/**********************************************************************/
Xvoid cleanup()
X{
X endwin();
X}
X
X
X/**********************************************************************/
X/**FUNCTION: printit() **/
X/** **/
X/**DESCRIPTION: This function print the childrens' actions. **/
X/** **/
X/**GLOBAL VARIABLES: none **/
X/** **/
X/**GLOBAL CONSTANTS: EATING, THINKING, HAS_ONE, HUNGRY **/
X/** **/
X/**CALLS: none **/
X/** **/
X/**RETURNS: none **/
X/**********************************************************************/
Xvoid printit(p_num,action)
X int p_num, action;
X{
X int x, y;
X char string[128];
X
X switch(action)
X {
X case EATING : (void)sprintf(string,"Philosopher %d is eating...",p_num);
X break;
X case THINKING : (void)sprintf(string,"Philosopher %d is thinking...",p_num);
X break;
X case HAS_ONE : if(!(p_num % 2))
X (void)sprintf(string,"Philosopher %d is hungry & has right chopstick...",p_num);
X else
X (void)sprintf(string,"Philosopher %d is hungry & has left chopstick...",p_num);
X break;
X case HUNGRY : (void)sprintf(string,"Philosopher %d is hungry...",p_num);
X break;
X default : return;
X }
X switch(p_num)
X {
X case 1: y = 2;
X x = 6;
X break;
X case 2 : y = 3;
X x = COLS - strlen(string) - 6;
X break;
X case 3 : y = LINES/2;
X x = COLS - strlen(string) - 2;
X break;
X case 4 : y = LINES - 2;
X x = COLS/2 - strlen(string)/2;
X break;
X case 5 : y = LINES/2 - 1;
X x = 2;
X break;
X default : return;
X }
X move(0,0);
X refresh();
X move(y,0);
X clrtoeol();
X mvaddstr(y,x,string);
X refresh();
X}
X
X
X/*************************************************************************/
X/**FUNCTION: V_semaphore() **/
X/** **/
X/**DESCRIPTION: This function releases the named semaphore in the set.**/
X/** It is called after a process leaves its critical section which is **/
X/** associated with 'sem_num'. **/
X/** **/
X/**GLOBAL VARIABLES: semid **/
X/** **/
X/**GLOBAL CONSTANTS: NUM_CHILDREN **/
X/** **/
X/**CALLS: cleanup() **/
X/** **/
X/**RETURNS: TRUE on success, otherwise FALSE. **/
X/*************************************************************************/
Xbool V_semaphore(sem_num)
X int sem_num;
X{
X int retrn;
X struct sembuf sembuf[NUM_CHILDREN], *sops;
X unsigned nsops = 1;
X
X sops = sembuf;
X sops->sem_num = sem_num;
X sops->sem_op = 1;
X sops->sem_flg = 0;
X if((retrn = semop(semid, sops, nsops)) == -1)
X {
X cleanup();
X perror("error with semop(semid,sops,nsops) in V_semaphore()");
X return(FALSE);
X }
X return(TRUE);
X}
X
X
X/*************************************************************************/
X/**FUNCTION: P_semaphore() **/
X/** **/
X/**DESCRIPTION: This function waits on the named semaphore in the set.**/
X/** It either blocks or not depending on 'block'. It is called **/
X/** before a process enters its critical section which is associated **/
X/** with 'sem_num'. **/
X/** **/
X/**GLOBAL VARIABLES: semid **/
X/** **/
X/**GLOBAL CONSTANTS: NUM_CHILDREN **/
X/** **/
X/**CALLS: cleanup() **/
X/** **/
X/**RETURNS: TRUE on success, FALSE otherwise--if block; TRUE if got **/
X/** semaphore, FALSE if not or error--if !block. **/
X/*************************************************************************/
Xbool P_semaphore(sem_num,block)
X int sem_num;
X bool block;
X{
X int retrn, flags = IPC_NOWAIT;
X struct sembuf sembuf[NUM_CHILDREN], *sops;
X unsigned nsops = 1;
X extern int errno;
X
X sops = sembuf;
X if(block)
X flags = 0;
X else
X errno = 0;
X sops->sem_num = sem_num;
X sops->sem_op = -1;
X sops->sem_flg = flags;
X if((retrn = semop(semid, sops, nsops)) == -1)
X {
X if(errno == EAGAIN) /* !block && didn't get semaphore */
X return(FALSE);
X cleanup();
X perror("error with semop(semid,sops,nsops) in P_semaphore()");
X return(FALSE);
X }
X return(TRUE);
X}
X
X
________This_Is_The_END________
if test `wc -l < phil.c` -ne 645; then
echo 'shar: phil.c was damaged during transit (should have been 645 bytes)'
fi
fi ; : end of overwriting check
exit 0
More information about the Comp.sources.misc
mailing list