2
\$\begingroup\$

I'm trying to implement a functional version of the classic reader-writer problem in IPC which doesn't cause starvation. You can find the full article here

The code is working. What do you think, is it coherent with the paper? How could I implement it using semop?

Here's the code

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <semaphore.h>
#include <fcntl.h>

#define TEST_ERROR    if (errno) {fprintf(stderr,           \
                      "%s:%d: PID=%5d: Error %d (%s)\n", \
                      __FILE__,         \
                      __LINE__,         \
                      getpid(),         \
                      errno,            \
                      strerror(errno));}

//third read-writer problem
int readers, writers;

int main()
{

    struct sembuf sops_mutex, sops_resource;
    int sem_mutex, sem_resource, shm_id, *list, i, j, status;
    pid_t child_pid;

    shm_id = shmget(IPC_PRIVATE, sizeof(list), 0666 | IPC_CREAT | IPC_EXCL); 
    TEST_ERROR;

    list = shmat(shm_id, NULL, 0);
    TEST_ERROR; 

    sem_mutex = semget((key_t)getpid(), 1, 0600 | IPC_CREAT | IPC_EXCL);
    TEST_ERROR;

    sem_resource = semget((key_t)getpid()+1, 1, 0600 | IPC_CREAT | IPC_EXCL); 
    TEST_ERROR;

    semctl(sem_mutex, 0, SETVAL, 1);          //signal(mutex)               
    semctl(sem_resource, 0, SETVAL, 1);       //signal(mutex)               



    //i%2==0 reader else writer
    for(i=0; i<20; i++) {
        switch(fork()) {
            case 0:


            switch(i%2) {
                case 0://reader

                    while(semctl(sem_mutex, 0, GETVAL) != 1); //wait(mutex)

                    if(writers > 0 || readers == 0) {
                        semctl(sem_mutex, 0, SETVAL, 1);          //signal(mutex)               
                        while(semctl(sem_resource, 0, GETVAL) != 1); //wait(mutex)
                        while(semctl(sem_mutex, 0, GETVAL) != 1); //wait(mutex)
                    }

                    readers++;
                    semctl(sem_mutex, 0, SETVAL, 1);          //signal(mutex)               

                    for(j = 0; j<20; j++) { //reading
                        if(j%2!=0)
                            printf("%lld %d ", (long long)getpid(), list[j]);
                    }printf("\n");

                    while(semctl(sem_mutex, 0, GETVAL) != 1); //wait(mutex)
                    readers--;
                    if(readers==0)
                        semctl(sem_resource, 0, SETVAL, 1);       //signal(resource)                
                    semctl(sem_mutex, 0, SETVAL, 1);          //signal(mutex)               


                    break;

                default://writer

                    while(semctl(sem_mutex, 0, GETVAL) != 1); //wait(mutex)
                    writers++;                                //writers <- +1
                    semctl(sem_mutex, 0, SETVAL, 1);          //signal(mutex)               
                    while(semctl(sem_resource, 0, GETVAL) != 1); //wait(resource)

                    list[i] = i; //writing

                    while(semctl(sem_mutex, 0, GETVAL) != 1); //wait(mutex)
                    writers--;                  
                    semctl(sem_mutex, 0, SETVAL, 1);          //signal(mutex)               
                    semctl(sem_resource, 0, SETVAL, 1);       //signal(resource)                

                    break;

            }

            shmdt(list);
            TEST_ERROR;         


            exit(0);
            break;

            default:
                break;

        }

    }

    while (shmctl(shm_id, IPC_RMID, NULL)) {
        TEST_ERROR;
    }

    while((child_pid = wait(&status)) != -1) {
        printf("PARENT: %lld, CHILD_TERMINATED: %d STATUS: %d \n", (long long)getpid(), child_pid, WEXITSTATUS(status));        
    }   

    semctl(sem_resource, 0, IPC_RMID);
    semctl(sem_mutex, 0, IPC_RMID); 

}

This is the wait-signal portion This is the wait-signal portion

And this is the code of interest Code of interest

\$\endgroup\$
  • \$\begingroup\$ @chux with testing you'll see that sometimes the readers can't read all the writings done, that's not an error i guess it's for scheduling reasons \$\endgroup\$ – Zeno Raiser Jan 3 '18 at 16:30
  • \$\begingroup\$ BTW: "%d" is not necessarily the matching specifier for the return type of getpid(). Usual fix is printf("%lld", (long long) getpid()); \$\endgroup\$ – chux Jan 3 '18 at 16:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.