0

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;
}
1
  • 1) There is no "array of struct". You have a pointer to pointer to struct, but likely want a "pointer to struct" according to your title. 2) Do not cast the result of malloc & friends in C. 3) Not sure, but if val is the shared array, why do you set the pointers to "private" memory? 4) You apparently have problems with the multiple indirection in various places. Commented Dec 30, 2015 at 18:08

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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;

Comments

1

You want to share the structs between processes, but instead you are sharing only pointers to structs. If those pointed to structs that were allocated and initialized before the fork then they would be valid in both processes, but would point to different copies of the structs (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 structs.

2 Comments

Maybe one should add that malloc never provides shared memory, but only private.
Clarified that malloc() allocates only private memory.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.