C语言中两个进程共享内存

unhi4e5o  于 2022-12-03  发布在  其他
关注(0)|答案(4)|浏览(326)

我想执行以下操作:
父进程创建一个子进程,然后子进程从用户那里读取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:random -ve数字在每次执行代码时都会改变 *

它从来没有通过子进程代码!我这样做的方式是错误的吗?

7rtdyuoh

7rtdyuoh1#

好吧,最好收集一个答案代替...
你的程序有几个问题。如果你在构建时启用警告(我使用-Wall -Wextra),很多问题都会很明显。
前两个问题我已经在我的评论中提到过,但我在这里解释一下:
1.第一个是对wait()的调用。在C或POSIX中没有不带参数的wait函数。
1.第二个问题是scanf调用,你用*++调用它,其中*nn指向的内存的 * 值 *,这很可能导致崩溃。删除星号。
1.第三个问题是,你把共享内存同时当作一个整数数组(n)和一个字符串,你不能两者都做,只能选一个。
1.您可以在父进程中创建共享内存,但要等到子进程完成后才能创建内存。
1.父进程和子进程之间存在争用情况,因为共享内存可能是在子进程尝试访问它之后创建的。

编辑我想出了这个方法,它似乎对我有用。我对我更改的内容添加了注解。

#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);

         char number[20];
         sprintf(number, "%d", n);  /* Convert the number to string */
         strcat(s, number);  /* Append the number to the 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点尚未解决。

xu3bshqb

xu3bshqb2#

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

shmid = shmget(2009, SHMSIZE, 0);

会变成这样:

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

感谢你们所有人,尤其是@JoachimPileborg:)

cdmah0mi

cdmah0mi3#

您的描述似乎不正确,因为没有输出“Parent Write〈〉"的代码。
您正在阅读数字并将其作为int存储在 *n++中,但随后您将一个'\n'字符追加到n-int数组中,并将shm视为字符串?
在我看来,在你的孩子中,你正在创建一个共享内存,写入它,然后关闭(丢弃)共享内存。然后你的第二部分打开一个新的共享内存,具有相同的段,但它是一个新的共享内存。通常一个进程创建一个共享内存,然后第二个进程打开它,当最后一个进程关闭共享内存时,它被操作系统释放。

4si2a6ki

4si2a6ki4#

一个问题是,子进程试图在父进程创建共享内存之前获取共享内存。父进程在创建共享内存之前有一个wait()调用,因此当客户端试图检索id时,共享内存将不存在。即使等待()呼叫被移动,它可能无法工作,因为存在争用条件。对shmget的调用可能需要在fork调用之前(或者在子进程中检索它之前,使用一些同步来确保它确实存在)。
而且(正如其他人已经指出的),孩子试图将整数写入内存,而阅读(打印)试图将其视为字符串。

相关问题