/* NOTE: compile with -lpthread */

#include <stdlib.h>

#include <stdio.h>

#include <pthread.h>

#include <unistd.h> //used for sleep()

#include <time.h> //used for time()

/* amount of philosophers */

#define THINKER_AMOUNT 5

typedef struct thinker_t thinker_t ;

struct thinker_t

{

// used to lock/unlock access to a fork

pthread_mutex_t fork_mutex ;

// used to wait for a fork to be available

pthread_cond_t fork_condition ;

int fork_in_use ; //0 if fork is available, 1 if in use

int time_remaining ; //how much eating time remains

int thinker_index ; //index of thinker

thinker_t * left ; //stores the left thinker

} ;

int init_thinkers ( thinker_t * philosophers , int philosopher_amount ) ;

void * thinker_thinks ( void * arg ) ;

int main ( ) {

//declare thinker arguments and threads

thinker_t thinker_list [ THINKER_AMOUNT ] ;

init_thinkers ( thinker_list , THINKER_AMOUNT ) ;

pthread_t thinker_threads [ THINKER_AMOUNT ] ;

//initiate random variables

srand ( time ( NULL ) ) ;

//create thinker threads

for ( int x = 0 ; x < THINKER_AMOUNT ; x ++ ) {

if ( pthread_create ( thinker_threads + x , NULL , thinker_thinks , thinker_list + x ) != 0 ) {

printf ( "ERROR: thread

" ) ;

return EXIT_FAILURE ;

}

}

//joins all threads

for ( int x = 0 ; x < THINKER_AMOUNT ; x ++ ) {

pthread_join ( thinker_threads [ x ] , NULL ) ;

}

return EXIT_SUCCESS ;

}

int init_thinkers ( thinker_t * philosophers , int philosopher_amount ) {

thinker_t * philosopher ;

for ( int x = 0 ; x < philosopher_amount ; x ++ ) {

philosopher = ( philosophers + x ) ;

philosopher -> fork_in_use = 0 ;

philosopher -> time_remaining = 30 ;

philosopher -> thinker_index = x ;

pthread_mutex_init ( & philosopher -> fork_mutex , NULL ) ;

if ( x != 0 ) philosopher -> left = philosopher - 1 ;

if ( pthread_cond_init ( & philosopher -> fork_condition , NULL ) != 0 ) {

printf ( "ERROR: condition variable

" ) ;

return EXIT_FAILURE ;

}

}

//sets first philosophers left as the last one

philosophers -> left = philosophers + philosopher_amount - 1 ;

return EXIT_SUCCESS ;

}

void * thinker_thinks ( void * arg ) {

thinker_t * current = ( thinker_t * ) arg ;

thinker_t * left = current -> left ;

int random_time ;

int eating_time = 3 ;

srand ( time ( NULL ) ^ pthread_self ( ) << 16 ) ;

while ( current -> time_remaining > 0 ) {

random_time = rand ( ) % 3 + 1 ;

sleep ( random_time ) ;

if ( current -> fork_in_use == 0 ) {

current -> fork_in_use = 1 ;

if ( left -> fork_in_use == 0 ) {

left -> fork_in_use = 1 ;

sleep ( eating_time ) ;

current -> time_remaining -= eating_time ;

printf ( "Philosopher %d has eaten a bit!

"

" \t Time Remainining to finish meal: %d seconds

" ,

current -> thinker_index , current -> time_remaining ) ;

left -> fork_in_use = 0 ;

sleep ( 1 ) ;

}

current -> fork_in_use = 0 ;

sleep ( 1 ) ;

}

}

printf ( "Philosopher %d has finished his meal!

" , current -> thinker_index ) ;

pthread_exit ( NULL ) ;