【问题标题】:Shared Memory With Two Processes In C?C语言中两个进程的共享内存?
【发布时间】:2012-01-01 11:37:48
【问题描述】:

我想做以下事情:

父进程创建一个子进程。然后子进程从用户那里读取 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 数字变化

它从未通过子进程代码!我这样做有错吗?

【问题讨论】:

  • 为什么不在parent中创建共享内存,然后运行child呢?
  • 父进程中第一次调用wait是什么?
  • 另外,你对scanf 的论点是错误的。
  • @K-ballo 我被要求这样做。我更愿意坚持这一点。
  • @JoachimPileborg wait() 是强制父母等待孩子完成。 scanf() 有什么问题?

标签: c fork shared-memory


【解决方案1】:

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

shmid = shmget(2009, SHMSIZE, 0);

会变成这样:

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

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

【讨论】:

  • 接受他的回答,让你们俩都抢点分数。 :)
  • 我对他的回答投了赞成票。我不能接受不能解决问题的答案,可以吗? :)
  • 假设 fork() 之后的代码是同时的和/或任何一个都可以先运行。因此,两个 shmget 都必须有 IPC_CREAT,所以谁先运行就会创建它。
【解决方案2】:

好的,最好收集一个答案...

你的程序有几个问题。如果您在构建时启用警告(我使用-Wall -Wextra),其中很多警告将非常明显。

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

  1. 首先是调用wait()。 C 或 POSIX 中没有不带参数的 wait 函数。
  2. 第二个问题是scanf 调用,您使用*++ 调用它,其中*n 采用n 指向的内存的值,这很可能会导致在崩溃中。去掉星号。
  3. 第三个问题是您将共享内存视为整数数组(使用n)和字符串。你不能两者都做,选择一个或另一个。
  4. 您在父进程中创建共享内存,但在创建内存之前等待子进程完成。
  5. 父进程和子进程之间存在竞争条件,因为共享内存可能是在子进程尝试访问它之后创建的。

编辑我想出了这个,这似乎对我有用。我在我改变的东西上添加了 cmets。

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

【讨论】:

  • 我现在将编辑我的代码。主要问题是代码正在工作但从未执行子块,即if(fork() == 0)块
  • 已更新。现在检查。仍然输出相同的一点点差异
  • @iturki 在我的答案中添加了代码,其中包含我对您的程序所做的更改。
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

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

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

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

    【讨论】:

    • 关闭 SHM 并不意味着丢弃它! shmdt() 表示:共享内存分离。 shmctl()SHM 销毁。关于输出,这是错误的。我会改正的。
    • 抱歉,我不熟悉 SHM API。但是,如果子进程调用 shmget 并随后终止,linux 不会隐含地破坏 SHM(在父进程打开它之前)吗?为什么你 IPC_CREAT 在父母身上,而不是在孩子身上?
    • 儿童只打开和关闭 SHM。然后,父级打开相同的 SHM,检索数据,关闭并销毁它。这就是它的工作原理。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-15
    • 1970-01-01
    • 2012-07-29
    • 1970-01-01
    • 2013-06-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多