Совместная память с двумя процессами в C? - PullRequest
4 голосов
/ 18 ноября 2011

Я хочу сделать следующее:

Родительский процесс создает дочерний процесс.Затем дочерний процесс читает n int от пользователя и сохраняет их в общей памяти.Затем родительский процесс отображает их.

Я достиг следующего:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#define SHMSIZE 27
int main() {
   int shmid;
   int *shm;
   int *n;

   if(fork() == 0) {
      shmid = shmget(2009, SHMSIZE, 0);
      shm = shmat(shmid, 0, 0);
      n = shm;
      int i;
      for(i=0; i<5; i++) {
         printf("Enter number<%i>: ", i);
         scanf("%d", n++);
      }
      printf ("Child wrote <%d>\n",shm);
      shmdt(shm);
   }
   else {
      wait();
      int *s;
      shmid = shmget(2009, SHMSIZE, 0666 | IPC_CREAT);
      shm = shmat(shmid, 0, 0);
      s = shm;
      wait(NULL);
      printf ("Parent reads <%d>\n",shm) ;
      shmdt(shm);
      shmctl(shmid, IPC_RMID, NULL);
   }
   return 0;
}

И вывод только этой строки:

Enter number<1>:

И если я ввел числоскажем, 25, он выводит это:

Parent reads <r>

r: случайное число меняется каждый раз, когда я выполняю код

Это никогда не проходило через дочерний процесскод!Я делаю это неправильно?

Ответы [ 4 ]

11 голосов
/ 18 ноября 2011

Хорошо, лучше соберите ответ вместо этого ...

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

Первые две проблемы, которые я уже упоминал в своих комментариях, но я объясняю их здесь:

  1. Первый вызов wait(). В C или POSIX нет функции wait, которая не принимает аргументов.
  2. Вторая проблема - это вызов scanf, вы вызываете его с помощью *++, где *n принимает значение памяти, на которую указывает n, что, скорее всего, может привести к авария Снимите звездочку.
  3. Третья проблема заключается в том, что вы используете общую память как массив целых чисел (с n) и как строку. Вы не можете сделать и то и другое, выберите одно или другое.
  4. Вы создаете общую память в родительском процессе, но дождитесь завершения дочернего процесса, прежде чем создавать память.
  5. Между родителем и дочерним процессом существует условие состязания, поскольку общая память может быть создана после того, как дочерний процесс попытается получить к ней доступ.

Редактировать Вместо этого я придумал, что, похоже, работает для меня. Я добавил комментарии на вещи, которые я изменил.

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <sys/wait.h>  /* Needed for the wait function */
#include <unistd.h>    /* needed for the fork function */
#include <string.h>    /* needed for the strcat function */
#define SHMSIZE 27
int main() {
   int shmid;
   char *shm;

   if(fork() == 0) {
      shmid = shmget(2009, SHMSIZE, 0);
      shm = shmat(shmid, 0, 0);
      char *s = (char *) shm;
      *s = '\0';  /* Set first location to string terminator, for later append */
      int i;
      for(i=0; i<5; i++) {
         int n;  /* Variable to get the number into */
         printf("Enter number<%i>: ", i);
         scanf("%d", &n);
         sprintf(s, "%s%d", s, n);  /* Append number to string */
      }
      strcat(s, "\n");  /* Append newline */
      printf ("Child wrote <%s>\n",shm);
      shmdt(shm);
   }
   else {
      /* Variable s removed, it wasn't used */
      /* Removed first call to wait as it held up parent process */
      shmid = shmget(2009, SHMSIZE, 0666 | IPC_CREAT);
      shm = shmat(shmid, 0, 0);
      wait(NULL);
      printf ("Parent reads <%s>\n",shm) ;
      shmdt(shm);
      shmctl(shmid, IPC_RMID, NULL);
   }
   return 0;
}

Обратите внимание, что пункт 5 в списке выше не был решен.

0 голосов
/ 19 ноября 2011

Моя проблема была такой глупой. Мне нужно предоставить процессу Child возможность записи в SHM. Эта строка в блоке if:

shmid = shmget(2009, SHMSIZE, 0);

Станет так:

shmid = shmget(2009, SHMSIZE, 0666 | IPC_CREAT);

Спасибо вам всем и особенно @JoachimPileborg:)

0 голосов
/ 18 ноября 2011

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

И (как уже указывали другие) ребенок пытается записать целые числа в память, в то время как чтение (печать его) пытается рассматривать его как символьную строку.

0 голосов
/ 18 ноября 2011

Похоже, что ваше описание неверно, поскольку нет кода, который выводит "Parent Wrote <>".

Вы читаете числа и сохраняете их как int в * n ++, но затем вы добавляете символ '\ n' в массив n-int и рассматриваете shm как строку?

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

...