简体   繁体   中英

Shared memory between N processes c

My goal here is to try to find a way to have multiple processes reading and writing on a shared memory. Until now I have been able to make only two processes communicate and I can't get around how to make more communicate. I'm making a project in which N processes A write their data on a shared memory and then N processes B read this shared memory and send their own data back to the process A that they decided to talk with. I must use shared memory and semaphores as well.

int main()
{


    const char* messageOne = "Hello world , I'm child number 1\n";
    const char* messageTwo = "Hello world , I'm child number 2\n";

    key_t key;
    char *virtualaddr;
    sem_t *get, *put;
    ssize_t numRead = -1;
    int shmid;

    const unsigned int commLen = strlen(messageOne) + 1;
    char buf[BUF_SIZE];

    key = ftok("anyfile",'R');

    shmid = shmget(key,1024,0644|IPC_CREAT);
    if (0 > shmid)
    {
        perror("Shared Mem creation error\n");
        exit(1);

    }
    //Attaching  the shared mem to my address space(available across fork)
    virtualaddr = shmat(shmid, (void*)0, 0);


    /*Create two POSIX Named Semaphores, get and put and initialising with 0*/
    get = sem_open("/get", O_CREAT|O_RDWR, 0644, 0);

    put = sem_open("/put", O_CREAT|O_RDWR, 0644, 0);

    // child 1
    switch (fork())
    {
        case -1:
            printf("Error forking child 1!\n");
            exit(1);
        case 0:
            printf("\nChild 1 executing...\n");
            //Referring the semaphores..
            get = sem_open ("/get", O_RDWR);
            put = sem_open ("/put", O_RDWR);

            //Child 1 writing in shared mem
            strcpy (virtualaddr, messageOne);
            //Child 1 signalling that now child 2 can write
            sem_post (get);
            //Child1 waiting for Child2 to write..
            sem_wait (put);
            //Child 1 reading from shared mem
            strcpy (buf, virtualaddr);
            printf("Message received child ONE: %s", buf);
            printf("Exiting child 1...\n");
            _exit(0);
            break;
        default:
            break;
    }
    // child 2
    switch (fork())
    {
        case -1:
            printf("Error forking child 2!\n");
            exit(1);
        case 0:
            printf("\nChild 2 executing...\n");
            //Referring the semaphores..
            get = sem_open ("/get", O_RDWR);
            put = sem_open ("/put", O_RDWR);

            //Waiting Till Child 1 has written.
            sem_wait (get);
            //Now child 2 can read from shared memory
            strcpy (buf, virtualaddr);
            //Child 2 writing in shared mem
            strcpy (virtualaddr,messageTwo );
            //Signalling that now Child 1 can read.
            sem_post (put);
            printf("Exiting child 2...\n");
            printf("Message received child TWO: %s", buf);
            _exit(EXIT_SUCCESS);
            break;

        default:
            break;
    }
    printf("Parent waiting for children completion...\n");

    if (wait(NULL) == -1)
    {
        printf("Error waiting.\n");
        exit(EXIT_FAILURE);
    }

    if (wait(NULL) == -1)
    {
        printf("Error waiting.\n");
        exit(EXIT_FAILURE);
    }

    printf("Parent finishing.\n");
    //Deleting semaphores..
    sem_unlink ("/get");
    sem_unlink ("/put");
    //Deleting Shared Memory.
    shmctl (shmid, IPC_RMID, NULL);
    exit(EXIT_SUCCESS);
}

I would like to adapt this code to multiple processes instead of two. If you have other options please feel free to post them.

Until now I have been able to make only two processes communicate and I can't get around how to make more communicate.

To extend your program for more than one child process pair, it is appropriate to use semaphore sets (of one semaphore per process) rather than plain semaphores. Below is a slightly modified variant of your program which does that for N pairs.

/* cc -std=c99 -lrt */
#define _SVID_SOURCE
#define _DEFAULT_SOURCE
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdatomic.h>

int main()
{
    key_t key;
    char *virtualaddr;
    int get, put;
    int shmid;
    #define BUF_SIZE    BUFSIZ
    char buf[BUF_SIZE];

    key = ftok("anyfile", 'R');
    #define N   4
    atomic_int *a;  // where the process counter is at the end of the shared mem
    shmid = shmget(key, 1024*N + sizeof*a, 0644|IPC_CREAT); // 1 kiB per process
    if (0 > shmid)
    {
        perror("Shared Mem creation error\n");
        exit(1);
    }
    //Attaching the shared mem to my address space (available across fork)
    virtualaddr = shmat(shmid, (void *)0, 0);
    a = (void *)&virtualaddr[1024*N];
    *a = 0;

    //Create two semaphore sets, get and put; Linux initializes the values to 0.
    get = semget('g', N, IPC_CREAT|0644);
    put = semget('p', N, IPC_CREAT|0644);

    for (int n = 0; n < N; ++n)
    // N children A
    switch (fork())
    {
        case -1:
            printf("Error forking child A!\n");
            exit(1);
        case 0:
            printf("\nChild A%d executing...\n", n);
            //Referring the semaphore sets:
            get = semget('g', 0, 0);
            put = semget('p', 0, 0);
            //Child A writing in shared mem
            sprintf(virtualaddr+1024*n, "Hello world, I'm child A%d\n", n);
            //Child A signalling that now child B can write
            semop(get, &(struct sembuf){ n, 1 }, 1);
            //Child A waiting for Child B to write..
            semop(put, &(struct sembuf){ n, -1 }, 1);
            //Child A reading from shared mem
            strcpy(buf, virtualaddr+1024*n);
            printf("Message received child A%d: %s", n, buf);
            printf("Exiting child A%d...\n", n);
            _exit(0);
            break;
        default:
            break;
    }
    for (int n = 0; n < N; ++n)
    // N children B
    switch (fork())
    {
        case -1:
            printf("Error forking child B!\n");
            exit(1);
        case 0:
            printf("\nChild B%d executing...\n", n);
            //Referring the semaphore sets:
            get = semget('g', 0, 0);
            put = semget('p', 0, 0);
            int i = (*a)++; // [somewhat] randomly select one of the A processes
            //Waiting till Child A has written
            semop(get, &(struct sembuf){ i, -1 }, 1);
            //Now child B can read from shared memory
            strcpy(buf, virtualaddr+1024*i);
            //Child B writing in shared mem
            sprintf(virtualaddr+1024*i, "Hello world, I'm child B%d\n", n);
            //Signalling that now Child A can read.
            semop(put, &(struct sembuf){ i, 1 }, 1);
            printf("Exiting child B%d...\n", n);
            printf("Message received child B%d: %s", n, buf);
            _exit(EXIT_SUCCESS);
            break;
        default:
            break;
    }
    printf("Parent waiting for children completion...\n");
    while (wait(NULL) > 0) ;
    if (errno != ECHILD)
    {
        printf("Error waiting.\n");
        exit(EXIT_FAILURE);
    }

    printf("Parent finishing.\n");
    //Deleting semaphore sets:
    semctl(get, 0, IPC_RMID);
    semctl(put, 0, IPC_RMID);
    //Deleting Shared Memory.
    shmctl (shmid, IPC_RMID, NULL);
    exit(EXIT_SUCCESS);
}

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