2015-12-30 1 views
0

Я использую массив структур для обмена данными между двумя процессами. Программа после 3 секунд повышает ошибку Segmentation fault, когда я пытаюсь получить доступ к общей памяти в родительский процесс. Почему данные неправильно распределены?Общая память с массивом структур

#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; 
} 
+0

1) Нет массива 'struct'. У вас есть указатель на указатель на 'struct', но, вероятно, вы хотите« указатель на 'struct'» в соответствии с вашим названием. 2) Не бросайте результат 'malloc' & friends в C. 3) Не уверен, но если' val' является общим массивом, почему вы устанавливаете указатели на «частную» память? 4) У вас, по-видимому, проблемы с множественной косвенностью в разных местах. – Olaf

ответ

2

Проблема заключается в том, что вы не разделяя массив структур, вы передаете массив указателей на структуры, и эти указатели указывают на не-разделяемую память вы выделяете с таНос. Вы хотите, чтобы код больше похож:

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; } 

То есть, использовать массив структур, а не массив указателей на структуры.

Обратите внимание, что это будет работать только в том случае, если в ваших структурах (и, следовательно, в вашей общей памяти) нет, то есть любые указатели в них - даже если указатели должны указывать на общую память, это могут быть разные адреса в различные процессы.

1

Вы хотите поделиться struct сек между процессами, но вместо этого вы используете только указатели на структуры. Если те указали на struct s, которые были выделены и инициализированы перед вилкой, тогда они будут действительны в обоих процессах, но будут указывать на разные копии struct s (malloc() выделяет только частную память, которая никогда не делится). Однако, как бы то ни было, указатели действительны только для ребенка, который выполняет malloc().

Таким образом, вместо того, чтобы массив указателей, выделить массив структур:

val_t *val; 

/* ... */ 

size = sizeof(val_t) * LEN; 

/* ... */ 

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

Если вы делаете это таким образом, к тому же, нет никакой необходимости malloc() (или free()) отдельных struct с.

+0

Возможно, следует добавить, что 'malloc' никогда не предоставляет разделяемую память, а только private. – Olaf

+0

Уточнено, что 'malloc()' выделяет только личную память. –

1

В,

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

val указывает на массив типа val_t* в совместно используемой памяти. Этот может получить доступ к в другом процессе, который подключается к одному и тому же сегменту разделяемой памяти.

Но,

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

val[i] указывает на памяти, выделяемой на malloc(), который является частным процессом. Этот указатель не может получить доступ к в другом процессе. Следовательно, Segmentation fault, когда вы делаете это в дочернем процессе.

val[0]->val = 3;