I need to create a Dining Philosophers Simulation in C++ using threads, locks, a
ID: 3569040 • Letter: I
Question
I need to create a Dining Philosophers Simulation in C++ using threads, locks, and condition variables. This will also use monitors.
I need to create a new CPP file based on the below:
Each philosopher is in one of 3 states, Hungry, Eating, or Thinking, and starts out in the Thinking state. When the philosopher is ready to eat, they change to Hungry. Before they can eat, they have to test to see if it's safe to do so. If either neighbor is Eating, it's not safe to eat, and they must wait until the situation changes, at which point they are in Eating state. When they're done, they go into Thinking state, and test to see if either neighbor is Hungry. If so, they notify that philosopher that it's safe to be Eating.
Here's my constructor, destructor, and private member functions from my ".h" file.
#ifndef __DINING_ROOM_H__
#define __DINING_ROOM_H__
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <pthread.h>
#include <ctype.h>
#include <unistd.h>
using namespace std;
class DiningRoom;
// Structure used to pass arguments to start_philosopher function
struct phil_args {
int phil_num;
int num_cycles;
DiningRoom *room;
};
// The DiningRoom class acts as a monitor for the simulation
class DiningRoom
{
private:
// Number of philosophers
int num_phils;
// Number of times each philosopher tries to eat
int num_cycles;
// An array containing the current state of each philosopher
int *phil_state;
// A lock used to protect the data in phil_state
pthread_mutex_t table_lock;
// An array of conditions used to make sure the philsophers don't eat until
// it is safe to do so
pthread_cond_t *safe_to_eat;
// An array of threads representing the philosophers
pthread_t *phil_threads;
// An array of structures used to pass arguments to the start_philosophers
// function
phil_args *args_array;
// Used for display functions
static const int WIDTH = 10;
// Used to represent philosopher states
static const int THINKING = 0;
static const int HUNGRY = 1;
static const int EATING = 2;
// Displays the headings for the state change table
void display_headings( )
{
cout << left;
for(int phil = 0; phil < num_phils; phil++) {
cout << "PHIL " << setw(WIDTH - 5) << phil;
}
cout << endl;
}
// Displays the current state of all philosophers.
// This should only be called if table_lock has been acquired
void display_states( )
{
for( int phil = 0; phil < num_phils; phil++) {
cout << left << setw(WIDTH);
switch(phil_state[phil]) {
case THINKING: cout << "THINKING"; break;
case HUNGRY: cout << "HUNGRY"; break;
case EATING: cout << "EATING"; break;
default: cout << "CONFUSED";
}
}
cout << endl;
cout.flush( );
}
// Gets the ID of the left neighbor of phil
int left_neighbor( int phil )
{
return phil == num_phils - 1? 0 : phil + 1;
}
// Gets the ID of the right neighbor of phil
int right_neighbor( int phil )
{
return phil == 0 ? num_phils - 1 : phil - 1;
}
// Tests to see if it is safe for the philosopher with the ID provided to eat
// If it is safe, it changes the philosopher's state to EATING and returns
// true, if not it returns false.
// This function must only be called after table_lock has been acquired
bool test( int phil ); /* IMPLEMENT THIS FUNCTION IN DiningRoom.cpp */
// Simulates a philosopher thinking
static void think( )
{
unsigned int seed = time(0);
srand(seed);
usleep(rand() % 500000);
}
// Simulates a philosopher eating
static void eat( )
{
unsigned int seed = time(0);
srand(seed);
usleep(rand() % 500000);
}
// Code for a philosopher thread to run.
// This function should be used when creating a new philosopher thread
static void *start_philosopher( void *_args )
{
phil_args *args = static_cast<phil_args *>(_args);
for(int i = 0; i < args->num_cycles; i++) {
think();
args->room->grab_forks(args->phil_num);
eat();
args->room->release_forks(args->phil_num);
}
return NULL;
}
public:
// Constructor
// num_phils is the number of philosophers
// num_cycles is the number of times each philosopher tries to eat
DiningRoom( int _num_phils, int _num_cycles )
{
// Initialize the simulation parameters
num_phils = _num_phils;
num_cycles = _num_cycles;
// Initialize the table lock
pthread_mutex_init(&table_lock, NULL);
// Create all of the arrays
phil_state = new int[num_phils];
safe_to_eat = new pthread_cond_t[num_phils];
phil_threads = new pthread_t[num_phils];
args_array = new phil_args[num_phils];
// Initialize the data in the arrays
for(int phil = 0; phil < num_phils; phil++) {
phil_state[phil] = THINKING;
pthread_cond_init(&safe_to_eat[phil], NULL);
args_array[phil].phil_num = phil;
args_array[phil].num_cycles = num_cycles;
args_array[phil].room = this;
}
}
// Destructor
~DiningRoom( )
{
delete [] phil_state;
delete [] safe_to_eat;
delete [] phil_threads;
delete [] args_array;
}
// Starts a dining philosopher simulation with parameters provided to the
// DiningRoom constructor.
void run_simulation( ); /* IMPLEMENT THIS FUNCTION IN DiningRoom.cpp */
// Simulates a philosopher picking up forks
void grab_forks( int phil ); /* IMPLEMENT THIS FUNCTION IN DiningRoom.cpp */
// Simulates a philosopher putting down forks
void release_forks( int phil ); /* IMPLEMENT THIS FUNCTION IN DiningRoom.cpp */
};
#endif
What I'm trying to do is implement the following member functions in my main cpp file:
void run_simulation() This starts a simulation of the problem:
- display headings for a table of state changes and a row of the table containing the philosohers' starting states
- start thread for each philosopher
- wait for each thread to complete
bool test(int phil) checks to see if it's safe to eat
- if the state for phil is Hungry, and neither neighbor is Eating, display current states of philosophers and return true
- otherwise return false
- the table lock must be acquired before this fctn is called
void grab_forks(int phil) simulates the pickup of forks
- acquire table lock
- set state for phil to Hungry
- display states
- test to see if it's safe to eat. If not, wait on the condition variable for phil in the safe_to_eat array
- release lock
void release_forks(int phil) simulates putting down the forks
- aquire lock
- set state of phil to Thinking
- display current states
- test to see if it's safe for neighbors to eat. If so, notify philosopher using the appropriate condition variable in the safe_to_eat array.
- release locks
Since I'm using pthreads, I need to:
- declare variable of type pthread_t
- write function whose argument and return value are of type void*
- create structure that can hold all the information the thread will need to execute, and create an instance of this structure containing the info for this thread
- start the thread using: pthread_create(&eThread, NULL, eFunction, &args);
- wait for the thread to complete using: pthread_join(eThread, NULL)
In order to create locks I must:
- create variable of type pthread_mutex_t
- initialize this var by using pthread_mutex_init(&eLock, NULL);
- when the currently running thread needs to acquire the lock, use: pthread_mutex_lock(&eLock);
To create and use a condition variable, I must:
- create variable of type pthread_cond_t
- to make current thread wait on the condition variable, use: pthread_cond_wait(&eCondition_Variable, &eLock)
Here's my sim, in another file
#include "DiningRoom.h"
#include <iostream>
#include <cstdlib>
using namespace std;
int main(int argc, char *argv[])
{
// Check to make sure there are two comand line arguments
if( argc < 2 ) {
cout << "Usage: dpsimulation num_phils num_cycles" << endl;
exit(1);
}
// Convert the command line arguments to integers
int num_phils = atoi(argv[1]);
int num_cycles = atoi(argv[2]);
// Create DiningRoom monitor object
DiningRoom room(num_phils, num_cycles);
// Run the simulation
room.run_simulation();
return 0;
}
I am maxing points on this one. Please help!
Explanation / Answer
#include<stdio.h>
#include<semaphore.h>
#include<pthread.h>
#define N 5
#define THINKING 0
#define HUNGRY 1
#define EATING 2
#define LEFT (ph_num+4)%N
#define RIGHT (ph_num+1)%N
sem_t mutex;
sem_t S[N];
void * philospher(void *num);
void take_fork(int);
void put_fork(int);
void test(int);
int state[N];
int phil_num[N]={0,1,2,3,4};
int main()
{
int i;
pthread_t thread_id[N];
sem_init(&mutex,0,1);
for(i=0;i<N;i++)
sem_init(&S[i],0,0);
for(i=0;i<N;i++)
{
pthread_create(&thread_id[i],NULL,philospher,&phil_num[i]);
printf("Philosopher %d is thinking ",i+1);
}
for(i=0;i<N;i++)
pthread_join(thread_id[i],NULL);
}
void *philospher(void *num)
{
while(1)
{
int *i = num;
sleep(1);
take_fork(*i);
sleep(0);
put_fork(*i);
}
}
void take_fork(int ph_num)
{
sem_wait(&mutex);
state[ph_num] = HUNGRY;
printf("Philosopher %d is Hungry ",ph_num+1);
test(ph_num);
sem_post(&mutex);
sem_wait(&S[ph_num]);
sleep(1);
}
void test(int ph_num)
{
if (state[ph_num] == HUNGRY && state[LEFT] != EATING && state[RIGHT] != EATING)
{
state[ph_num] = EATING;
sleep(2);
printf("Philosopher %d takes fork %d and %d ",ph_num+1,LEFT+1,ph_num+1);
printf("Philosopher %d is Eating ",ph_num+1);
sem_post(&S[ph_num]);
}
}
void put_fork(int ph_num)
{
sem_wait(&mutex);
state[ph_num] = THINKING;
printf("Philosopher %d putting fork %d and %d down ",ph_num+1,LEFT+1,ph_num+1);
printf("Philosopher %d is thinking ",ph_num+1);
test(LEFT);
test(RIGHT);
sem_post(&mutex);
}
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.