Thread: Process based circular buffer not working

  1. #16
    Registered User
    Join Date
    May 2020
    Posts
    29
    I'm now using virtualbox to test the code shmget is now working but shmat is giving permission denied.

    So I changed shmget to const int shared_mem_id = shmget(IPC_PRIVATE, 2 * sizeof(sem_t), IPC_CREAT | 0660);
    Last edited by Redsam121; 05-17-2020 at 08:46 AM.

  2. #17
    Registered User
    Join Date
    May 2020
    Posts
    29
    The code is now going through the input successfully, but for some reason this isn't printing
    Code:
    fprintf(share->out, "Lift-%d Operation\r\n"        "Previous position: Floor %d\r\n"
            "Request: Floor %d to Floor %d\r\n"
            "Detail operations:\r\n"
            "    Go from Floor %d to Floor %d\r\n"
            "    Go from Floor %d to Floor %d\r\n"
            "    #movement for this request: %d\r\n"
            "    #request: %d\r\n"
            "    Total #movement: %d\r\n"
            "Current Position: Floor %d\r\n"
            "\r\n"
            "----------------------------\r\n", id, write1->p, write1->rf, write1->rt, write1->p, write1->rf, write1->rf, write1->rt
                , write1->m, write1->total_r[id], write1->total_m[id], write1->c);
    here is what I've done so far:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <unistd.h> 
    #include <semaphore.h>
    #include <sys/mman.h>
    #include <sys/ipc.h>
    #include <sys/shm.h> 
    #include <sys/stat.h>
    #include <fcntl.h> 
    #include "list.h"
    #include <errno.h>
    sem_t *full, *empty; //Semaphore mutex intializer
    static int *counter; //number of requests made
    static int size; //buffer size (must only change once at beginning)
                     //Doesn't need to be in shared memory because it will be the same for all processes.
    static int sec; //Time in seconds, needed for lift to execute operation
    static int *length; //Number of values in buffer
                       //Will be shared across processes using mmap.
    static int *in; //index of reader
    static int *out_i; //index of writer
    static buffer_t *A;
    static write_t *write1; //Used for printing the information from buffer.
    void *lift(void* vargp) //Consumer
    {
        share_t* share = vargp;
        while (true)
        {
            while (*length <= 0)
            {
                sem_wait(empty);
                printf("Waiting for request\n");
            }
            sleep(sec);
            printf("lifting information\n");
            printf("%d %d \n", A[*out_i].from, A[*out_i].to);
            int id = share->id;
            //gather information to print
            if (write1->p == 0) //only for when system begins (Assign Previous to the first record `from` value)
            {
                write1->p = A[*out_i].from;
            }
            write1->rf = A[*out_i].from;
            write1->rt = A[*out_i].to;
            write1->m = (write1->p - A[*out_i].from) + (A[*out_i].to - A[*out_i].from);
            write1->c = A[*out_i].to;
            //Now write the information
            write1->total_r[id] = write1->total_r[id] + 1;
            write1->total_m[id] = write1->total_m[id] + write1->m;
            fprintf(share->out, "Lift-%d Operation\n"
            "Previous position: Floor %d\n"
            "Request: Floor %d to Floor %d\n"
            "Detail operations:\n"
            "    Go from Floor %d to Floor %d\n"
            "    Go from Floor %d to Floor %d\n"
            "    #movement for this request: %d\n"
            "    #request: %d\n"
            "    Total #movement: %d\n"
            "Current Position: Floor %d\n"
            "\n"
            "----------------------------\n", id, write1->p, write1->rf, write1->rt, write1->p, write1->rf, write1->rf, write1->rt
                , write1->m, write1->total_r[id], write1->total_m[id], write1->c);
            write1->p = write1->c; //for next statement
            *length = *length - 1;
            *out_i = (*out_i + 1) % size;
            if (*length == 0)
            {
                printf("Signalling lift\n");
                sem_post(full);
            }
        }
        
        return NULL;
    }
    void *request_t(void *vargp) //producer
    {
        share_t* share = vargp;
        while(1)
        {
            while (*length >= size)
            {
                sem_wait(full);
                printf("Waiting for lift\n");
            }
            printf("Requesting information\n");
            //read the input line by line and into the buffer
            if (fscanf(share->in, "%d %d\n", &A[*in].from, &A[*in].to) == EOF)
            {
                break;//stop the loop when file is empty
            }
            printf("%d %d \n", A[*in].from, A[*in].to);
            //If requests go out of bounds, they will be automatically registered as either
            //maximum level or minimum level
            if (A[*in].to > 20)
            {
                A[*in].to = 20;
            }
            else if (A[*in].to < 1)
            {
                A[*in].to = 1;
            }
            else if (A[*in].from > 20)
            {
                A[*in].from = 20;
            }
            else if (A[*in].from < 1)
            {
                A[*in].from = 1;
            }
            //Print buffer information to sim_output
            fprintf(share->out, "New Lift Request from Floor %d to Floor %d \n"
            "Request No %d \n"
            "----------------------------\n", A[*in].from, A[*in].to, * counter = *counter + 1);
            *length = *length + 1;
            *in = (*in + 1) % size;
            if (*length == 1)
            {
                printf("Signalling request\n");
                sem_post(empty);
            }
        }
        return NULL;
    }
    int main(int argc, char *argv[]) // to avoid segmentation fault
    {
        //establish values for use (convert argv to int values)
        if (argc != 3) //Must have both m and t
        {
            perror("Insufficient arguements\n");
            exit(EXIT_FAILURE);
        }
        long arg = strtol(argv[1], NULL, 10);
        size = arg;
        if (size <= 1)
        {
            perror("buffer size too small\n");
            exit(0);
        }
        //allow variables to be shared among processes without duplicates being made
        in = mmap(NULL, sizeof * in, PROT_READ | PROT_WRITE,
            MAP_SHARED | MAP_ANONYMOUS, -1, 0);
        out_i = mmap(NULL, sizeof * out_i, PROT_READ | PROT_WRITE,
            MAP_SHARED | MAP_ANONYMOUS, -1, 0);
        length = mmap(NULL, sizeof * length, PROT_READ | PROT_WRITE,
            MAP_SHARED | MAP_ANONYMOUS, -1, 0);
        counter = mmap(NULL, sizeof * counter, PROT_READ | PROT_WRITE,
            MAP_SHARED | MAP_ANONYMOUS, -1, 0);
        write1 = mmap(NULL, sizeof * write1, PROT_READ | PROT_WRITE,
            MAP_SHARED | MAP_ANONYMOUS, -1, 0);
        *length = 0, *in = 0, *out_i = 0, *counter = 1;
        //initialize Buffer as empty array and as shared memory.
        A = mmap(NULL, sizeof * A, PROT_READ | PROT_WRITE,
            MAP_SHARED | MAP_ANONYMOUS, -1, 0);
        for (int i = 0; i < size + 1; i++) //Had to be changed from calloc to for loop due to errors in mmap()
        {                                  //Caused lift to print 0 instead of read values
            A[i].from = 0;
            A[i].to = 0;
        }
        arg = strtol(argv[2], NULL, 10);
        sec = arg; //time required by each lift to serve a request
        if (sec <= 0)
        {
            perror("insufficient time\n");
            exit(0);
        }
        //open files for reading and writing
        FILE *out = fopen("sim_output.txt", "w");
        FILE *in_t = fopen("sim_input.txt", "r");
        if (in == NULL && out == NULL) //Check if files exists before we can use them
        {
            perror("Input file empty\n");
            exit(0);
        }
        //Create a shared memory for the file streams
        //it is important the algorithm keeps a consistent stream of values
        share_t *share[4];
        for (int i = 0; i < 4; i++)//Load files into share for transporting.
        {
            share[i] = mmap(NULL, sizeof * share, PROT_READ | PROT_WRITE,
                MAP_SHARED | MAP_ANONYMOUS, -1, 0);
            share[i]->in = in_t;
            share[i]->out = out;
            share[i]->id = i;
        }
        //Create processes
        printf("Creating processes\n");
        const int shared_mem_id = shmget(IPC_PRIVATE, 2 * sizeof(sem_t), IPC_CREAT | 0660);//must allocate space for two semaphores
        sem_t *two_sems = shmat(shared_mem_id, NULL, 0);
        if (errno) perror("E2");
        full = &two_sems[0];
        empty = &two_sems[1];
        sem_init(full, 1, 1);//stops here
        sem_init(empty, 1, 1);
        pid_t Lift_R = fork();
        if (Lift_R == 0) { // Lift-R Child Proccess
            request_t(share[0]);
            shmdt(full);
            exit(0);
        }
        else if (Lift_R == -1)//Error detection
        {
            perror("could not wait for child\n");
            exit(0);
        }
        pid_t lift_1 = fork();
        if (lift_1 == 0) { // lift-1 Child Proccess
            lift(share[1]);
            shmdt(empty);
            exit(0);
        }
        else if (lift_1 == -1)
        {
            perror("could not wait for child\n");
            exit(0);
        }
        pid_t lift_2 = fork();
        if (lift_2 == 0) { // lift-2 Child Proccess
    
            printf("B\n");
            lift(share[2]);
            shmdt(empty);
            exit(0);
        }
        else if (lift_2 == -1)
        {
            perror("could not wait for child\n");
            exit(0);
        }
        pid_t lift_3 = fork();
        if (lift_3 == 0) { // lift-3 Child Proccess
    
            printf("C\n");
            lift(share[3]);
            shmdt(empty);
            exit(0);
        }
        else if (lift_3 == -1)
        {
            perror("could not wait for child\n");
            exit(0);
        }
        Lift_R = wait(NULL);
        int sum_r = write1->total_r[1] + write1->total_r[2] + write1->total_r[3],
            sum_t = write1->total_m[1] + write1->total_m[2] + write1->total_m[3]; //Create total sums of requests and movement
        fprintf(out, "\r\n"
            "Total number of requests %d \r\n"
            "Total number of movememts %d \r\n", sum_r, sum_t); //Print at the very last line after all requests were made
        fclose(in_t);
        fclose(out);
        printf("finished\n");
        exit(1);
        lift_1 = wait(NULL);
        printf("1\n");
        lift_2 = wait(NULL);
        printf("2\n");
        lift_3 = wait(NULL);
        printf("3\n");
    }

  3. #18
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Code:
        //open files for reading and writing
        FILE *out = fopen("sim_output.txt", "w");
        FILE *in_t = fopen("sim_input.txt", "r");
        if (in == NULL && out == NULL) //Check if files exists before we can use them
        {
            perror("Input file empty\n");
            exit(0);
        }
        //Create a shared memory for the file streams
        //it is important the algorithm keeps a consistent stream of values
        share_t *share[4];
        for (int i = 0; i < 4; i++)//Load files into share for transporting.
        {
            share[i] = mmap(NULL, sizeof * share, PROT_READ | PROT_WRITE,
                MAP_SHARED | MAP_ANONYMOUS, -1, 0);
            share[i]->in = in_t;
            share[i]->out = out;
    in == NULL isn't testing your opened file, just some random global variable also called in.

    That share->in and share-out isn't going to work. The FILE* pointer might be in shared memory, but other things internal to it (like say a buffer) won't be in shared memory, and thus will not persist properly across a fork (you don't go onto call execl).

    fork(2): create child process - Linux man page
    The fork() environment is a weird place.
    99% of the time, people just use it as a jumping off point for calling execl.
    It's not normally a place where you do substantial work.


    Back to files:
    In main, do
    int in_fd = open("sim_input.txt", O_RDONLY);
    int out_fd = open("sim_output.txt", O_WRONLY|O_CREAT|O_TRUNC, 0660);

    Then share these descriptors.

    In each function, you can get back to a FILE* with dfopen, such as
    FILE *in_f = fdopen(share->in_fd, "r");
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Pthread Circular buffer not looping, need help!
    By Redsam121 in forum C Programming
    Replies: 28
    Last Post: 05-15-2020, 10:24 PM
  2. Circular buffer - console crashing
    By High Voltage in forum C++ Programming
    Replies: 10
    Last Post: 02-26-2017, 08:59 AM
  3. Circular Buffer using Virtual Memory
    By SMurf in forum Windows Programming
    Replies: 5
    Last Post: 03-26-2013, 07:05 PM
  4. Circular buffer - logic difficulty
    By erasm in forum C Programming
    Replies: 2
    Last Post: 10-05-2009, 01:08 PM
  5. Circular Buffer
    By parisframe in forum C Programming
    Replies: 11
    Last Post: 09-16-2009, 11:05 PM

Tags for this Thread