/** * Dining Philosophers solution using simultaneous Wait and Signal on a Unix semaphore array * This solution uses a global array of semaphores "table" * main method, create, initializes, and destroy "table" array * Philo method, uses the "table" array to access concurrently chopsticks and let philosophers to eat * * Ubuntu: install "libncurses5" and "libncurses5-dev" * **/ #include #include #include #include #include #include #include #include "Semaphore.h" #define NUMWORKERS 5 Semaphore * table; Semaphore * mutex; // Need to be init to 1 int main ( int argc, char *argv[] ); void Philo ( int arg ); /* * Curses display */ void displayTitle() { WINDOW * title; char title0[ 128 ] = "\t CI-0122 Sistemas Operativos\n"; char title1[ 128 ] = "\t ------------------------------------------------------------\n"; char title2[ 128 ] = "\t| Process | Philosopher | Status | Chopstick 1 | Chopstick 2 |\n"; char title3[ 128 ] = "\t|------------------------------------------------------------|"; title = newwin( 4, 80, 0, 1 ); waddstr( title, title0 ); waddstr( title, title1 ); waddstr( title, title2 ); waddstr( title, title3 ); wrefresh( title ); } /** * Display philosopher information using curses */ void displayPhilosopher( int who, int state ) { WINDOW * philoWin; int posx, posy; char buffer[ 128 ]; char bottomLine[ 128 ] = "\t|------------------------------------------------------------|\n"; char lastLine[ 128 ] = "\t ------------------------------------------------------------"; char chop1[ 8 ] = "--"; char chop2[ 8 ] = "--"; char displayState[ 8 ] = ""; switch ( state ) { case 0: // Thinking sprintf( displayState, "%6s", "Think " ); break; case 1: // Hungry sprintf( displayState, "%6s", "Hungry" ); break; case 2: // Eating sprintf( displayState, "%6s", "Eating" ); sprintf( chop1, "%2d", who ); sprintf( chop2, "%2d", (who + 1) % NUMWORKERS ); break; case 3: // Finished sprintf( displayState, "%6s", "Ended " ); break; } // Choose window position according to philospher number, depends on title posy = (who + 2) * 2; posx = 1; mutex->Wait(); philoWin = newwin( 2, 80, posy, posx ); // nlines, ncols, beginy, beginx if ( 4 >= who ) { sprintf( buffer, "\t| %5d | %1d | %6s | %2s | %2s |\n", getpid(), who + 1, displayState, chop1, chop2 ); } else { sprintf( buffer, "\n" ); } waddstr( philoWin, buffer ); // Check last line to display if ( who + 1 == NUMWORKERS ) { waddstr( philoWin, lastLine ); } else { waddstr( philoWin, bottomLine ); } wrefresh( philoWin ); delwin( philoWin ); mutex->Signal(); } int main ( int argc, char *argv[] ) { int i, pindex, worker, status; pid_t workers[ NUMWORKERS ]; // curses initialization initscr(); cbreak(); noecho(); displayTitle(); srand( time( NULL ) ); table = new Semaphore( NUMWORKERS ); mutex = new Semaphore( 1, 1 ); for ( i = 0; i < NUMWORKERS; i++ ) { // Start workers status = fork(); if ( ! status ) { // Child code Philo( i ); } else { workers[ i ] = status; } } for ( i = 0; i < NUMWORKERS; i++ ) { worker = waitpid( -1, &status, 0 ); // Wait for any of the started processes // worker = waitpid( workers[ i ], &status, 0 ); // Wait for started processed in order pindex = -1; do { // Find out which worker finished pindex++; } while ( pindex < NUMWORKERS && worker != workers[ pindex ] ); displayPhilosopher( pindex, 3 ); if ( -1 == worker ) { perror( "main" ); } } delete table; echo(); nocbreak(); endwin(); printf( "\nNormal end of execution.\n" ); return 0; } /** * Simulates the philosopher behaviour repeat for ever (sleep, eat) * Each process do the cycle 10 times */ void Philo( int who ) { int eats, thinks; for ( int i = 0; i < 10; i++ ) { // Each worker takes 10 rounds // Initial think cycle (sleep) displayPhilosopher( who, 0 ); thinks = rand() % 2000000; usleep( thinks ); // Initial sleep displayPhilosopher( who, 1 ); table->SP( who, (who + 1) % NUMWORKERS ); // Do a simultaneous wait on both semaphores // Eat time eats = rand() % 2000000; displayPhilosopher( who, 2 ); usleep( eats ); // Return chopsticks table->SV( who, (who + 1) % NUMWORKERS ); // Do a simultaneous signal of both semaphores // Second think cycle thinks = rand() % 2000000; displayPhilosopher( who, 0 ); usleep( thinks ); } _exit( 0 ); }