Frage

I'm working on assignment where the professor is asking for a solution to solve the dinning philosopher problem using semaphores.

Here is my code so far:

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>

#define MAX_THINKING_TIME 1500  /* maximum thinking time in milliseconds */
#define MIN_THINKING_TIME 1000  /* minimum thinking time in milliseconds */
#define MAX_EATING_TIME   1000  /* maximum eating time in milliseconds */
#define MIN_EATING_TIME   750   /* minimum eating time in milliseconds */

/*
 * Macros to encapsulate the POSIX semaphore functions.
 */
#define semaphore_create(s,v)   sem_init( &s, 0, v )
#define semaphore_wait(s)           sem_wait( &s )
#define semaphore_signal(s)         sem_post( &s )
#define semaphore_release(s)    sem_destroy( &s )
typedef sem_t semaphore;

// Each chopstick is represented by a semaphore (shared between all processes).
semaphore *chopstick;

int NUM_PHILOSOPHERS; /* number of philosophers */
int NUM_REPETITIONS;  /* number of cycles */

/*
 * Generating a random number within a range.
 */
unsigned int randr(unsigned int min, unsigned int max)
{
    double scaled = (double)rand()/RAND_MAX;
    return (max - min +1) * scaled + min;
}

/*
 * To pick up his chopsticks, a philosopher does a semaphore wait on each.
 * Alternating order prevents deadlock.
 */
void pickup_chopsticks(int index)
{
    if(index % 2 == 0) /* Even number: Left, then right */
    {
        semaphore_wait(chopstick[(index+1) % NUM_PHILOSOPHERS]);
        printf("Philosopher #%d: I am picking up the left chopstick!\n", index+1);
        semaphore_wait(chopstick[index]);
        printf("Philosopher #%d: I am picking up the right chopstick!\n", index+1);
    }
    else /* Odd number: Right, then left */
    {
        semaphore_wait(chopstick[index]);
        printf("Philosopher #%d: I am picking up the right chopstick!\n", index+1);
        semaphore_wait(chopstick[(index+1) % NUM_PHILOSOPHERS]);
        printf("Philosopher #%d: I am picking up the left chopstick!\n", index+1);
    }
}

/*
 * To drop his chopsticks, a philosopher does a semaphore signal on each.
 * Order does not matter.
 */
void drop_chopsticks(int index)
{
    printf("Philosopher #%d: I am dropping the right chopstick!\n", index+1);
    semaphore_signal(chopstick[index]);
    printf("Philosopher #%d: I am dropping the left chopstick!\n", index+1);
    semaphore_signal(chopstick[(index+1) % NUM_PHILOSOPHERS]);
}

/*
 * Simulate a philosopher - endlessly cycling between eating and thinking
 * until his "life" is over.
 */
void start_philosopher(int index)
{
    int i; // A counter.

    for(i = 0; i < NUM_REPETITIONS; i++)
    {
        /* Hungry */
        printf("Philosopher #%d (Cycle #%d): I am hungry!\n", index+1, i+1);
        pickup_chopsticks(index);

        /* Eating */
        printf("Philosopher #%d (Cycle #%d): I am eating!\n", index+1, i+1);
        usleep(1000 * randr(MIN_EATING_TIME, MAX_EATING_TIME));
        drop_chopsticks(index);

        /* Thinking */
        printf("Philosopher #%d (Cycle #%d): I am thinking!\n", index+1, i+1);
        usleep(1000 * randr(MIN_THINKING_TIME, MAX_THINKING_TIME));
    }

    printf("Philosopher #%d: I am dead!\n", index+1);
    exit(0);
}

/*
 * The main function.
 */
int main(int argc, char *argv[])
{

    // If the input arguments are not 2 elements, display a message and return.
    if(argc != 3)
    {
        printf("You have to insert arguments in the form:\n");
        printf("Number_of_Philosopher Number_of_repeats\n");
        return -1;
    }

    // Set value of NUM_PHILOSOPHERS and NUM_REPETITIONS from the user input.
    NUM_PHILOSOPHERS = atoi(argv[1]);
    NUM_REPETITIONS  = atoi(argv[2]);
    int i; // A counter.

    // Allocate memory for the semaphores.
    chopstick = malloc(NUM_PHILOSOPHERS * sizeof(semaphore));

    // Create semaphores to represent "one user at a time" chopsticks.
    for(i = 0; i < NUM_PHILOSOPHERS; i++)
        semaphore_create(chopstick[i], 1);

    // Create n processes for n philosophers
    for(i = 0; i < NUM_PHILOSOPHERS; i++)
    {
        if(fork() == 0) start_philosopher(i);
        else wait();
    }
    // Release semaphore resources.
    for(i = 0; i < NUM_PHILOSOPHERS; i++)
        semaphore_release(chopstick[i]);

    // Free the memory.
    free(chopstick);

    return 0;
}

and when I run it, I got the following:

$ ./run 2 2
Philosopher #1 (Cycle #1): I am hungry!
Philosopher #1: I am picking up the left chopstick!
Philosopher #1: I am picking up the right chopstick!
Philosopher #1 (Cycle #1): I am eating!
Philosopher #1: I am dropping the right chopstick!
Philosopher #1: I am dropping the left chopstick!
Philosopher #1 (Cycle #1): I am thinking!
Philosopher #1 (Cycle #2): I am hungry!
Philosopher #1: I am picking up the left chopstick!
Philosopher #1: I am picking up the right chopstick!
Philosopher #1 (Cycle #2): I am eating!
Philosopher #1: I am dropping the right chopstick!
Philosopher #1: I am dropping the left chopstick!
Philosopher #1 (Cycle #2): I am thinking!
Philosopher #1: I am dead!
Philosopher #2 (Cycle #1): I am hungry!
^Z
[6]+  Stopped                 ./run 2 2

As you can see, I have two problems:

  • Process n+1 is not executing unless process n is done.
  • In previous test of running the program, it's being stuck at when the second philosopher is requesting for picking up the chopsticks. It seems that the semaphore is not signaled and the philosopher is waiting for a signal.

Can you please help me to fix the program?

War es hilfreich?

Lösung

Problem (1) is solved by moving the wait() outside the loop performing the fork.

Problem (2) is solved by allocating the memory using mmap() with the MAP_SHARED flag to allow it to be shared amongst the children, and using the sem_init(&s, 1, v) option for the sem_init call - using the 0 as the second option means that it is for intra-process (i.e. in the same pid, without being a child using fork).

chopstick = mmap(0, NUM_PHILOSOPHERS * sizeof(semaphore), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);

Andere Tipps

In the loop where you fork new processes, the new parent process (where fork returns non-zero) you wait for the new process to finish. Drop the else and call wait outside the loop.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top