简体   繁体   中英

inter process communication using shared memory(mmap) and semaphores

I am trying to improvise a program I had written for single producer multiple consumer multi threading using counting semaphores. I want to implement inter process communication using shared memory (mmap() system call). I want to use anonymous mapping with no backing file.

This is the structure I want to share between the parent and its multiple child processes.

typedef struct Buffer{
    char **Tuples;
    sem_t buf_mutex,empty_count,fill_count;
} Buffer;
Buffer buffer[100];

The parent process is the mapper() function which does produces something and puts it in buffer[i], based on some inputs. The child processes go to reducer() function which consumes what is put in its buffer[j]. Each reducer or child process should have access to its buffer. The child processes are forked() in the main function and then the parent process control goes to mapper() . I have initialized the synchronization primitives to be process shared.

Is my main() method the correct way of doing it ? I am also getting type casting errors for return value of mmap() , which is a pointer, but I am not sure how to handle it and then use it. I also think malloc() should not be used in line 47 for allocating space to tuples but instead mmap() itself should be used. Can anyone please help ? This is my program -

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/mman.h>

typedef struct Buffer{
    char **Tuples;
    // int count;
    sem_t buf_mutex,empty_count,fill_count;
} Buffer;
Buffer buffer[100];
int numOfSlots;
int numOfReducers;

void mapper(){
    //Synchronization primitives (counting semaphores) used for synchronization
    //Produce something and put it in buffer[i]
}

void reducer(long b){
    //Synchronization primitives (counting semaphores) for synchronization
    //Consume from buffer[b]
}


int main (int argc, char *argv[]){
    if(argc != 3) {
        if(argc < 3)
            printf("Insufficient arguments passed\n");
        else
            printf("Too many arguments passed\n");
    return 1;
    }
    int i;
    long r;
    numOfSlots = atoi(argv[1]);
    numOfReducers = atoi(argv[2]);

    for(i=0; i<numOfReducers; i++){
        buffer[i] = (struct Buffer *) mmap(NULL, sizeof(buffer[i]), PROT_READ | PROT_WRITE,
                MAP_SHARED | MAP_ANONYMOUS, -1, 0);
        if (buffer[i] == MAP_FAILED)
            errExit("mmap");    

        buffer[i].Tuples = malloc(numOfSlots * sizeof(char *));
        sem_init(&buffer[i].buf_mutex, 1, 1);
        sem_init(&buffer[i].fill_count, 1, 0);
        sem_init(&buffer[i].empty_count, 1, numOfSlots);
    }

    for(r=0;r<numOfReducers;r++){ // loop will run n times (n=5)
        if(fork() == 0){
            printf("[son] pid %d from [parent] pid %d\n",getpid(),getppid());
            Reducer(r);
            exit(0);
        }
    }
    mapper();
    for(r=0;r<numOfReducers;r++) // loop will run n times (n=5)
    wait(NULL);
}

These are the links I am trying to follow - https://computing.llnl.gov/tutorials/pthreads/man/pthread_mutexattr_init.txt https://github.com/bradfa/tlpi-dist/blob/master/mmap/anon_mmap.c

Thanks, Harrish

After researching on the net. I came up with this solution which works. One more thing I learnt is char *var="hello" is stored in read only memory in the text segment, which means the child processes can also access it. So strcpy() would be a better option for anything else.

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <string.h>

typedef struct Buffer{
    char **Tuples;
    // int count;
    sem_t buf_mutex,empty_count,fill_count;
    int inSlotIndex;
    int outSlotIndex;
} Buffer;
Buffer *buffer;
int numOfSlots;
int numOfReducers;
int *done;

void mapper(){
//Synchronization primitives (counting semaphores) used for synchronization
//read continuously from a file, produce something and put it in buffer[i]
//Here is an example
    char *temp = "trail";
    sem_wait(&buffer[1].empty_count);
    sem_wait(&buffer[1].buf_mutex);
    // Use strcpy() for anything other than string literal
    buffer[1].Tuples[0] = temp;
    buffer[1].inSlotIndex = 3;
    buffer[1].outSlotIndex = 4;
    sem_post(&buffer[1].buf_mutex);
    sem_post(&buffer[1].fill_count);
    *done = 1;
}

void reducer(long tid, Buffer *buffer, int *done){
//Synchronization primitives (counting semaphores) used for synchronization
//Consume from buffer[b]
    sem_wait(&buffer[tid].fill_count);
    sem_wait(&buffer[tid].buf_mutex);
    printf("%s\n", buffer[tid].Tuples[0]);
    printf("%d\n", buffer[tid].inSlotIndex);
    printf("%d\n", buffer[tid].outSlotIndex);
    sem_post(&buffer[tid].buf_mutex);
    sem_post(&buffer[tid].empty_count);
    if(*done == 1)
        printf("DONE\n");
}


int main (int argc, char *argv[])
{
    if(argc != 3) {
        if(argc < 3)
            printf("Insufficient arguments passed\n");
        else
            printf("Too many arguments passed\n");
        return 1;
    }
    srand(time(NULL));
    int i, j;
    long r;
    char *temp;
    numOfSlots = atoi(argv[1]);
    numOfReducers = atoi(argv[2]);

    buffer = (struct Buffer *)mmap(NULL, numOfReducers * sizeof(struct Buffer), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    if(buffer == MAP_FAILED){
        printf("EXITING");
        exit(EXIT_FAILURE);
    }
    done = (int *)mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    if (done  == MAP_FAILED){
        printf("exiting\n");
    }
    *done = 0;

    for(i=0; i<numOfReducers; i++){
        buffer[i].Tuples = mmap(NULL, numOfSlots * sizeof(char *), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
        if(buffer[i].Tuples == MAP_FAILED){
            printf("EXITING");
            exit(EXIT_FAILURE);
        }
        for(j=0; j<numOfSlots; j++){
            temp = (char *)mmap(NULL, 30 * sizeof(char), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
            temp = strcpy(temp, "");
            buffer[i].Tuples[j] = temp;
        }
        sem_init(&buffer[i].buf_mutex, 1, 1);
        sem_init(&buffer[i].fill_count, 1, 0);
        sem_init(&buffer[i].empty_count, 1, numOfSlots);
    }

    for(r=0;r<numOfReducers;r++){ // loop will run n times (n=5)
        if(fork() == 0){
            printf("[son] pid %d from [parent] pid %d\n",getpid(),getppid());
            reducer(r, buffer, done);
            exit(0);
        }
    }
    mapper();
    for(r=0;r<numOfReducers;r++) // loop will run n times (n=5)
    wait(NULL);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM