c - 管道、子进程和子进程的范围

标签 c unix concurrency pipe fork

我在上操作系统课,我有一个处理 fork 和管道的项目。在开始我的项目之前,我试图更好地理解 fork 和管道,所以我正在研究一个例子。这是有问题的代码(当 pid=fork() 等于 0 并且是子进程时的情况 0):

switch(pid = fork())

{

case -1:

  perror("fork call");
  exit(2);
  break;
case 0:
  char str1[MSGSIZE]; 
  char str2[MSGSIZE]; 
  char str3[MSGSIZE];
  printf("Enter a string! ");
  fgets(str1, MSGSIZE, stdin);
  printf("Enter another string! ");
  fgets(str2, MSGSIZE, stdin);

  printf("Enter the last string! ");
  fgets(str3, MSGSIZE, stdin);


  close(p[0]);
  write(p[1], msg1, MSGSIZE);
  write(p[1], msg2, MSGSIZE);
  write(p[1], msg3, MSGSIZE);
  printf("About to write str1,str2,str3...\n");
  write(p[1], str1, MSGSIZE);
  write(p[1], str2, MSGSIZE);
  write(p[1], str3, MSGSIZE);
  break;
default:
  close(p[1]);
  for(j = 0; j < 6; j++)
  {
    read(p[0], inbuf, MSGSIZE);
    printf("%s\n", inbuf);
  }
  wait(NULL);   

  }//switch

当我在命令行上编译时出现这些错误:

$ gcc -o p3 pipe3.c

pipe3.c:45:7: 错误:预期的表达式 字符 str1[MSGSIZE]; ^

pipe3.c:49:13: 错误:使用了未声明的标识符 'str1' fgets(str1, MSGSIZE, 标准输入); ^

pipe3.c:62:19: 错误:使用了未声明的标识符 'str1' 写(p[1], str1, MSGSIZE); ^

产生了 3 个错误。

我最初在 main 函数的开头声明了 str1、str2 和 str3(我知道此时它仍然是父进程)并且在编译时没有出现这些错误。我试图在子进程中声明这些的唯一原因是因为我试图了解子进程的范围以及它的能力,这意味着我只是想尝试并思考什么是合法的和非法的.我真的不明白为什么编译器关心子进程是创建和初始化变量然后只在子进程范围内使用它们写入管道的进程。所以我想我想问的主要问题是,这实际上是管道的限制吗?我尝试使用 char *str1;在子进程中,然后也使用 fgets 存储输入,但我仍然遇到相同的编译器错误。另外,我是否认为子进程的范围只是 case 0: 和 break; 之间的代码是错误的?或者子进程是否获得父程序的完整副本,因为父进程中的其余代码被忽略,因为子进程执行代码的唯一时间是 pid == 0?我知道这可能是一些基础知识,但操作系统是让我作为一名程序员彻底难过的第一门课。

为了上下文和完整性,这是我的整个源代码:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#define MSGSIZE 16
int main(int argc, char *argv[])
{
  char inbuf[MSGSIZE];
  char *msg1 = "Hello world #1";
  char *msg2 = "Hello world #2";
  char *msg3 = "Hello world #3";
  char str1[MSGSIZE]; 
  char str2[MSGSIZE]; 
  char str3[MSGSIZE];

  int  p[2], j;
  pid_t pid;    

  if(pipe(p) == -1)
  {
    perror("pipe call");
    exit(1);
  }

  switch(pid = fork())
  {

case -1:

  perror("fork call");
  exit(2);
  break;
case 0:
  //char *str1; 
  //char *str2; 
  //char *str3;
  printf("Enter a string! ");
  fgets(str1, MSGSIZE, stdin);
  printf("Enter another string! ");
  fgets(str2, MSGSIZE, stdin);

  printf("Enter the last string! ");
  fgets(str3, MSGSIZE, stdin);


  close(p[0]);
  write(p[1], msg1, MSGSIZE);
  write(p[1], msg2, MSGSIZE);
  write(p[1], msg3, MSGSIZE);
  printf("About to write the input strings...\n");
  write(p[1], str1, MSGSIZE);
  write(p[1], str2, MSGSIZE);
  write(p[1], str3, MSGSIZE);
  break;
default:
  close(p[1]);
  for(j = 0; j < 6; j++)
  {
    read(p[0], inbuf, MSGSIZE);
    printf("%s\n", inbuf);
  }
  wait(NULL);   

  }//switch

  return 0;
}

最佳答案

标准 C(C99 之前)需要在 block 的开头声明变量。从这个意义上说,函数(包括 main)是一个 bloc。

switch 可以是一个 block ,但 case 不是,因此您不能在 case 中声明新变量。 真正的 错误在编译器不接受的 char str1[MSGSIZE]; 处,因此未声明 str1 是什么导致了2 个其他错误。

如果你只想在 child 中声明变量(这对你作为程序员有意义,但对编译器没有意义:fork 只是它的一个函数)你可以在两种方式:

  • 一个干净的方法是将它放在一个函数中并调用该函数:

    void doCopy(int *p) {
      char str1[MSGSIZE]; 
      char str2[MSGSIZE]; 
      char str3[MSGSIZE];
      printf("Enter a string! ");
      fgets(str1, MSGSIZE, stdin);
      printf("Enter another string! ");
      fgets(str2, MSGSIZE, stdin);
    
      printf("Enter the last string! ");
      fgets(str3, MSGSIZE, stdin);
    
    
      close(p[0]);
      write(p[1], msg1, MSGSIZE);
      write(p[1], msg2, MSGSIZE);
      write(p[1], msg3, MSGSIZE);
      printf("About to write the input strings...\n");
      write(p[1], str1, MSGSIZE);
      write(p[1], str2, MSGSIZE);
      write(p[1], str3, MSGSIZE);
    }
    
    int main(int argc, char *argv[])
    ...
            case 0:
                doCopy(p, MSGSIZE);
                break;
    ...
    
  • 一种不太惯用但可编译的方法是强制创建带有dummy 的 bloc,如果:

    ...
      switch(pid = fork())
      {
    
    case -1:
    
      perror("fork call");
      exit(2);
      break;
    case 0:
      if(1) {
          char str1[MSGSIZE]; 
          char str2[MSGSIZE]; 
          char str3[MSGSIZE];
          printf("Enter a string! ");
          fgets(str1, MSGSIZE, stdin);
          printf("Enter another string! ");
          fgets(str2, MSGSIZE, stdin);
    
          printf("Enter the last string! ");
          fgets(str3, MSGSIZE, stdin);
    
    
          close(p[0]);
          write(p[1], msg1, MSGSIZE);
          write(p[1], msg2, MSGSIZE);
          write(p[1], msg3, MSGSIZE);
          printf("About to write the input strings...\n");
          write(p[1], str1, MSGSIZE);
          write(p[1], str2, MSGSIZE);
          write(p[1], str3, MSGSIZE);
      }
      break;
    default:
    ...
    

关于c - 管道、子进程和子进程的范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30019499/

相关文章:

c# - 从 C header 自动创建 C# 包装器?

c++ - 如何让 XCode 6 在调用 Debugger() 时不停止执行?

shell - 在unix工作目录中查找特定目录

java - `Future<?>` 任务完成后检查字段是否安全?

c - sig_atomic_t 实际上是如何工作的?

使用 memcpy 从缓冲区的第二个元素复制到其他缓冲区

c - Getopt 为特定的选项顺序返回 -1

regex - 如何使用 bash 脚本验证电子邮件 ID?

java - ThreadPoolExecutor中的 "active threads"是什么意思?

concurrency - 什么是内存栅栏?