简体   繁体   中英

Shared memory with array of structs

I'm using an array of structs for share data between two process. The program after 3 secs raise an Segmentation fault error, when I try to access to the shared memory into the parent process. Why the data is not correctly shared?

#include <stdio.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#define LEN     3

typedef struct {
    int val;
} val_t;

int
main (int argc, char *argv[])
{
    key_t   key;
    int     shmid, i, size;
    val_t   **val;

    if ((key = ftok(argv[0], 'D')) == -1) {
        perror("ftok");
        exit(1);
    }

    size = sizeof(val_t *) * LEN;

    if (fork() == 0) {
        if ((shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0666)) == -1) {
            perror("shmget");
            exit(1);
        }

        val = (val_t **) shmat(shmid, 0, 0);
        if (val == (val_t **)(-1)) {
            perror("shmat");
            exit(1);
        }

        for (i = 0; i < LEN; i++) {
            val[i] = (val_t *) malloc(sizeof(val_t));
            val[i]->val = i;
        }

        while (val[0]->val != 3)
            sleep(1);

        if (shmdt(val) == -1) {
            perror("shmdt");
            exit(1);
        }
        shmctl(shmid, IPC_RMID, NULL);
    }
    else {
        sleep(3);

         if ((shmid = shmget(key, size, IPC_EXCL)) == -1) {
            perror("shmget");
            exit(1);
        }

        val = (val_t **) shmat(shmid, 0, 0);
        if (val == (val_t **)(-1)) {
            perror("shmat");
            exit(1);
        }

        printf("%d\n", val[0]->val);
        val[0]->val = 3;

        if (shmdt(val) == -1) {
            perror("shmdt");
            exit(1);
        }
    }

    return 0;
}

The problem is that you're not sharing an array of structs, you're sharing an array of pointers to structs, and those pointers point into non-shared memory you allocate with malloc. You want code more like:

val_t   *val;
size = sizeof(val_t) * LEN;

if (fork() == 0) {
    if ((shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0666)) == -1) {
        perror("shmget");
        exit(1); }

    val = (val_t *) shmat(shmid, 0, 0);
    if (val == (val_t *)(-1)) {
        perror("shmat");
        exit(1); }

    for (i = 0; i < LEN; i++) {
        val[i].val = i; }

That is, use an array of structs, rather than an array of pointers to structs.

Note that this will only work as long as your structs (and thus your shared memory) never have any pointers in them -- even if the pointers were to point at shared memory, it might be at different addresses in the different processes.

You want to share the struct s between processes, but instead you are sharing only pointers to structs. If those pointed to struct s that were allocated and initialized before the fork then they would be valid in both processes, but would point to different copies of the struct s ( malloc() allocates only private memory, never shared). As it is, however, the pointers are only valid in the child, which is the one performing the malloc() .

So, instead of an array of pointers, allocate an array of structs:

val_t *val;

/* ... */

size = sizeof(val_t) * LEN;

/* ... */

val = (val_t *) shmat(shmid, 0, 0);

If you do it this way, moreover, there is no need to malloc() (or free() ) individual struct s.

In,

val = (val_t **) shmat(shmid, 0, 0);

val points to an array of type val_t* in shared memory. This can be accessed in another process that attaches to the same shared memory segment.

But in,

val[i] = (val_t *) malloc(sizeof(val_t));

val[i] points to memory allocated by malloc() which is private to a process. This pointer cannot be accessed in a different process. Hence the Segmentation fault when you do this in the child process.

val[0]->val = 3;

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