【问题标题】:reading a value from a pipe isn't working从管道读取值不起作用
【发布时间】:2015-01-02 02:50:02
【问题描述】:

我有一个程序,其中创建了属于同一个父亲的两个子进程。现在程序从按控制 C 开始,然后每次按控制 Z 运行。

目标是让孩子 1 向孩子 2 写入两个数字,然后孩子 2 将数字相除并将结果写回显示它的孩子 1。因此需要两个管道(fd 和 sd)。

我的第一个管道工作正常,所以数字正在发送……在子 2(用于调试)中,它显示正确的数字,所以如果它有 8 和 2……显示正确的答案 4在孩子 2 中。现在我似乎无法将这个“4”或任何结果返回给孩子 1。

#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>


void handleSignal(int sig)
{
  if (sig == SIGTSTP)
    {
      return;
    }
}

int main()
{
    int fd[2];
    int sd[2];
    int pipe1 = 0;
    int pipe2 = 0;
    pid_t fork1 = 0;
    pid_t fork2 = 0;
    int num1, num2, result;
    int myJump = 0; 
    int returnResult = 99;

    signal(SIGINT, handleSignal);
    printf("Waiting for interrupt\n");
    pause();
    signal(SIGINT, SIG_IGN);
    pipe1 = pipe(fd);
    pipe2 = pipe(sd);
    //pipe checks been omitted...for simplicity

    fork1 = fork();
    //fork check been omited..for simplicity

    signal(SIGTSTP, handleSignal); //wait till control Z is pressed

    if (fork1 == 0)
    {

        dup2(fd[1], 1);
    dup2(sd[0], 0);
        close(fd[0]);
    close(sd[1]);

    while(1)
      {
            pause();
            int randNum1 = rand() % 9 + 1;
            fprintf(stderr, "Child 1: %d\n", randNum1);
            printf("%d\n", randNum1);
            fflush(stdout);
        scanf("%d", &returnResult);
        fprintf(stderr, "result in A :%d \n", returnResult);
      }

    }
    else if (fork1 > 0)
    {
      fork2 = fork();

      if (fork2 == 0)
        {
      signal(SIGTSTP, handleSignal);
      dup2(fd[0], 0);
      dup2(sd[1], 1);
      close(fd[1]);
      close(sd[0]);

      if (myJump == 0)
        {
          pause();
          scanf("%d", &num1);
          printf("CHild 2: %d\n", num1);
          myJump = 1;
        }
      if (myJump == 1)
        {
          while (1)
        {
          pause();
          scanf("%d", &num2);
          result = num2 / num1;
          fprintf(stderr, "result from B: %d \n", result);
          num1 = num2;
          printf("%d \n", result);
        }
        }

    }
      else
    {
      wait();
    }
    }
    else
      {
    printf("errror \n");
      }

    return 0;
}

如果有人能看出什么是错的,如果你要运行它......它首先点击控制 C 然后你必须继续点击控制 Z。然后你可以看到孩子 A 的结果与那个不匹配B的如下图

Waiting for interrupt
^C^ZChild 1: 2
result in A :99 
^ZChild 1: 8
result in A :99 
result from B: 4 
^ZChild 1: 1
result in A :99 
result from B: 0 

【问题讨论】:

    标签: c unix pipe fork


    【解决方案1】:

    管道实际上工作正常... scanf() 失败了。当您的第二个子进程启动时,它会调用:

      if (myJump == 0)
        {
          pause();
          scanf("%d", &num1);
          printf("CHild 2: %d\n", num1); /* <== problem here */
          myJump = 1;
        }
    

    ...printf() 留下“CHild 2:”作为sd[] 管道中的下一个数据。因此,当您的第一个子进程调用 scanf() 从第二个子进程读取结果时,scanf() 失败并保持 returnResult 不变。由于scanf() 失败,数据留在流中,以后尝试scanf() 结果以同样的方式失败。

    如何解决它取决于您想要什么。如果您希望您的第二个子进程只返回它读取的数字作为第一次传递的结果,那么只需修改有问题的 printf() 以仅写入不带文本的数字:

      if (myJump == 0)
        {
          pause();
          scanf("%d", &num1);
          printf("%d\n", num1); /* <== Changed: number only, no text */
          myJump = 1;
        }
    

    我要补充一点,虽然上面提到的更改会解决问题,但您通常应该检查来自scanf() 的返回,看看它是否成功,如果不成功,请采取适当的措施。

    【讨论】:

    • 我认为'Child 2' 打印很可能实际上应该进入标准错误,以便监控进程的人可以看到它,而不是发送到其他进程。调试信息通常会发送到stderr,因为它不会从管道中消失并阻塞它们。 (另见Getting a parent and child process to work using signals。)
    • @JonathanLeffler 不过,另一个孩子希望在那时收到一个号码。如果将 fprintf 更改为 stderr,他需要添加另一个 printf 以将数字也发送到其他进程。
    猜你喜欢
    • 2022-11-10
    • 2014-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 1970-01-01
    • 1970-01-01
    • 2021-12-11
    相关资源
    最近更新 更多