共享内存有两个进程在C?

时间:2011-11-18 18:08:08

标签: c fork shared-memory

我想做以下事情:

父进程创建子进程。然后子进程从用户读取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:每次执行代码时随机-ve数都会改变

它从未经历过子进程代码!我这样做是错误的吗?

4 个答案:

答案 0 :(得分:11)

好的,请更好地收集答案......

您的程序存在一些问题。如果您在构建时启用警告(我使用-Wall -Wextra),其中很多都会非常明显。

我在评论中已经提到的前两个问题,但我在这里解释一下:

  1. 第一个是对wait()的调用。 C或POSIX中没有wait函数不带参数。
  2. 第二个问题是scanf调用,您使用*++调用它,其中*n获取n指向的内存的 1}}最有可能导致崩溃。删除星号。
  3. 第三个问题是您将共享内存视为整数数组(使用n)和字符串。你不能真的做到这两个,选择其中一个。
  4. 您在父进程中创建共享内存,但在创建内存之前等待子进程完成。
  5. 父进程和子进程之间存在竞争条件,因为在子进程尝试访问它之后可能会创建共享内存。
  6. 编辑我想出了这个,这似乎对我有用。我对我改变的事情添加了评论。

    #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点尚未解决。

答案 1 :(得分:0)

您的描述似乎不正确,因为没有输出“Parent Wrote&lt;&gt;”的代码。

您正在读取数字并将它们存储为* n ++中的int,但是您在n-int数组中附加了一个'\ n'字符并且您将shm视为字符串?

在我看来,在你的孩子中,你正在创建一个共享内存,写入它然后关闭(丢弃)共享内存。然后你的第二部分打开一个具有相同段的新共享内存,但它是一个新的共享内存。通常,一个进程创建一个共享内存,然后第二个进程打开它,当最后一个进程关闭共享内存时,它将被操作系统释放。

答案 2 :(得分:0)

一个问题是子进程在父进程创建之前尝试使用获取共享内存。在创建共享内存之前,父进程有wait()调用,因此当客户端尝试检索id时它不存在。即使移动了wait()调用,它也可能无效,因为存在竞争条件。对shmget的调用可能需要在fork调用之前(或者使用某些同步来确保它在子进程中检索它之前确实存在)。

并且(正如其他人已经指出的那样),孩子正在尝试将整数写入内存,而阅读(打印它)则试图将其视为字符串。

答案 3 :(得分:0)

我的问题太愚蠢了。我需要为Child进程提供写入SHM的能力。 if-block中的这一行:

shmid = shmget(2009, SHMSIZE, 0);

会变成这样:

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

感谢大家,尤其感谢@JoachimPileborg:)