0

Generalities and functioning of my program

NB : you will be able to test my program (only one file, containing the main function). I give you the entire code at the end of this question.

I wrote a program which can be used to illustrate the producer-consumer algorithm, with UNIX-Processes. The producer creates some value, for example 5, writes it into a RAM shared_buffer and then writes the latter into a file test.txt. The consumer assigns to this shared_buffer the content of the file test.txt and takes some value from the RAM buffer, shared_buffer.

I use functions to convert my shared_buffer into the file, and reciprocally : arrayToFile and fileToArray. Both are presented at the end of this question.

The shared_buffer has a size of 1 + 10 cases : the first one contains the number of full cases (ie. : with a 5 writen) and the 10 others can be filled either with 5 or nothing. The first case is useful for the producer, to know where to write next value (ie. : in which case). The file of course has also 1 + 10 cases. The file is needed because I use processes and not threads (not-shared memory, thus).

shared_buffer's initialisation is contained in the main function. shared_buffer's accesses (in reading and in writing) are contained in consumer's function and in producer's function, respectively. These codes are presented at the end of this question.

Access to shared_buffer and overall to the file are of course under mutual exclusion and three semaphores are used. The mutexe impedes producer and consumer to access it at the same time, and the two other semaphores are used to guarantee that the producer won't try to put a new element if there isn't enough place, and that the consumer won't try to take an element if there isn't any element. Well, it's just the producer-consumer algorithm.

Finally, producer's process runs until the end of time, and so does the consumer's process.

The declaration and initialisation of these three semaphores are presented at the end of this question.


My problem

There is only one problem : when both producer's process and consumer's process are running until the end of times while(TRUE), arrayToFile and fileToArray tell me that the file's opening failed. If I erase one or both while(TRUE), this error disapears (but thus, my program doesn't make its job).

So this problem appears only when both while(TRUE) are writen.

I think it's because I don't make good use of the mutexe. But I couldn't give you more explanations.


Source

Code is highly commented.

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/sem.h>
#include <stdlib.h>

#define TRUE 1
#define ERR_NBR_ARGS "ERROR. Argument needed. Use as follows.\n"

int fileToArray(char *, int *, int);
int arrayToFile(char *, int *, int);

void check_if_command_arguments_are_correct(int);
void mutual_exclusion_produce(int, char*, int*, int);
void mutual_exclusion_consume(int, char*, int*, int);

int main(int argc, char* argv[]) {

    check_if_command_arguments_are_correct(argc);

    // FILE'S PATH
    char* file_path = argv[1];

    // DECLARATION AND INITIALISATION OF THE SHARED RESOURCE
    int shared_buffer_number_of_elements = 10;
    int shared_buffer[shared_buffer_number_of_elements + 1];
    shared_buffer[0] = 0;
    arrayToFile(file_path, shared_buffer, shared_buffer_number_of_elements);

    // FILE'S KEY (used to make processes able to use the same semaphores)
    key_t key = ftok(argv[0], '0');
    if(key == - 1) {
        perror("ftok");
        exit(EXIT_FAILURE);
    }

    // DECLARATION AND INITIALISATION OF THE THREE SEMAPHORES
    int semid = semget(key, 3, IPC_CREAT|IPC_EXCL|0666); // Declaration of the semaphores
    if(semid == -1) {
        perror("semget");
        exit(EXIT_FAILURE);
    }

    int array_semaphores_values[3];
    array_semaphores_values[0] = 1;
    array_semaphores_values[1] = shared_buffer_number_of_elements;
    array_semaphores_values[2] = 0;
    int sem_controller = semctl(semid, 3, SETALL, array_semaphores_values); // Initialisation of the semaphores - 2th parameter is the array's size
    if(sem_controller == -1) {
        perror("semctl");
        exit(EXIT_FAILURE);
    }

    // THE TWO FORKS - CREATION OF BOTH PRODUCER AND CONSUMER
    pid_t producer = fork();
    if(producer == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    } else if(producer == 0) { // The producer process

        mutual_exclusion_produce(semid, file_path, shared_buffer, shared_buffer_number_of_elements);

    } else { // The main process

        pid_t consumer = fork();
        if(consumer == - 1) {
            perror("fork");
            exit(EXIT_FAILURE);
        } else if(consumer == 0) { // The consumer process

            mutual_exclusion_consume(semid, file_path, shared_buffer, shared_buffer_number_of_elements);

        }
    }

    semctl(semid, 0, IPC_RMID, 0); // The semaphores are freed
}

void mutual_exclusion_produce(int semid, char* file_path, int* buffer, int size) {
    /* The producer does the following :
     * 1. It decrements the free cases semaphore ;
     * 2. It decrements the mutex ;
     * 3. It writes the buffer
     * 4. It increments the mutex ;
     * 5. It increments the full cases semaphore ;
     * */

    while(TRUE) {
        // DECREMENTS FREE CASES SEMAPHORE AND DECREMENTS MUTEX
        struct sembuf operation_decrement_free_cases;
        operation_decrement_free_cases.sem_num = 2;
        operation_decrement_free_cases.sem_op = -1;
        operation_decrement_free_cases.sem_flg = 0;

        struct sembuf operation_decrement_mutex;
        operation_decrement_mutex.sem_num = 0;
        operation_decrement_mutex.sem_op = -1;
        operation_decrement_mutex.sem_flg = 0;

        semop(semid, &operation_decrement_free_cases, 0);
        semop(semid, &operation_decrement_mutex, 0);

        // WRITES THE BUFFER INTO THE FILE
        buffer[++buffer[0]] = 5;
        arrayToFile(file_path, buffer, size);

        // INCREMENTS THE MUTEX AND INCREMENTS THE FULL CASES SEMAPHORE
        struct sembuf operation_increment_full_cases;
        operation_decrement_free_cases.sem_num = 1;
        operation_decrement_free_cases.sem_op = +1;
        operation_decrement_free_cases.sem_flg = 0;

        struct sembuf operation_increment_mutex;
        operation_decrement_mutex.sem_num = 0;
        operation_decrement_mutex.sem_op = +1;
        operation_decrement_mutex.sem_flg = 0;

        semop(semid, &operation_increment_mutex, 0);
        semop(semid, &operation_increment_full_cases, 0);
    }
}

void mutual_exclusion_consume(int semid, char* file_path, int* buffer, int size) {
    /*
     * The consumer does the following :
     * 1. It decrements the full cases semaphore ;
     * 2. It decrements the mutex ;
     * 3. It reads the buffer ;
     * 4. It increments the mutex ;
     * 5. It increments the free cases semaphore ;
     * */

    while(TRUE) {
        // DECREMENTS FULL CASES SEMAPHORE AND DECREMENTS MUTEX
        struct sembuf operation_decrement_full_cases;
        operation_decrement_full_cases.sem_num = 1;
        operation_decrement_full_cases.sem_op = -1;
        operation_decrement_full_cases.sem_flg = 0;

        struct sembuf operation_decrement_mutex;
        operation_decrement_mutex.sem_num = 0;
        operation_decrement_mutex.sem_op = -1;
        operation_decrement_mutex.sem_flg = 0;

        semop(semid, &operation_decrement_full_cases, 0);
        semop(semid, &operation_decrement_mutex, 0);

        // READS THE FILE AND PUT THE CONTENTS INTO THE BUFFER
        fileToArray(file_path, buffer, size);

        // INCREMENTS THE MUTEX AND INCREMENTS THE FREE CASES SEMAPHORE
        struct sembuf operation_increment_free_cases;
        operation_decrement_full_cases.sem_num = 2;
        operation_decrement_full_cases.sem_op = +1;
        operation_decrement_full_cases.sem_flg = 0;

        struct sembuf operation_increment_mutex;
        operation_decrement_mutex.sem_num = 0;
        operation_decrement_mutex.sem_op = +1;
        operation_decrement_mutex.sem_flg = 0;

        semop(semid, &operation_increment_mutex, 0);
        semop(semid, &operation_increment_free_cases, 0);
    }
}

void check_if_command_arguments_are_correct(int argc) {
    if(argc != 2) {
        fprintf(stderr, ERR_NBR_ARGS);
        fprintf(stderr, "program_command <file_buffer>\n");
        exit(EXIT_FAILURE);
    }
}

int fileToArray(char *pathname, int *tab, int size) {
    int cible;
    if ( (cible  = open(pathname,O_RDONLY)) < 0){
        fprintf(stderr,"fileToArray - impossible to open the file\n");
        return -1;
    }

    if (read(cible,tab,(size+1) * sizeof(int)) !=(size+1) * sizeof(int)) {
        fprintf(stderr,"fileToArray - impossible to read the file\n");
        return -1;
    }
    close(cible);
    return 0;
}

int arrayToFile(char *pathname, int *tab, int size) {
    int cible;

    if ( (cible  = open(pathname,O_WRONLY|O_CREAT|O_TRUNC,0666)) < 0){
        fprintf(stderr,"arrayToFile - impossible to open the file\n");
        return -1;
    }

    if (write(cible,tab,(size+1) * sizeof(int)) !=(size+1) * sizeof(int)) {
        fprintf(stderr,"arrayToFile - impossible to write the file\n");
        return -1;
    }
    close(cible);
    return 0;
}
JarsOfJam-Scheduler
  • 2,809
  • 3
  • 31
  • 70

0 Answers0