尝试终止时,使用管道的C程序挂起

时间:2019-12-04 06:16:36

标签: c operating-system switch-statement pipe fork

exact

在上面的程序中,我有一个父级,使两个子进程属于同一父级。用户写入父进程,该进程通过管道传递要由子1或子2读取的消息。除非用户输入-1,否则它将持续进行此操作。

问题是我的switch语句中的情况没有执行,而是程序挂起。我认为我的管道在正确的地方关闭了。

2 个答案:

答案 0 :(得分:0)

首先,您需要开始执行错误检查。检查您拨打的电话的手册页。在代码中添加检查以检测错误。当他们返回错误时,请使用perrorexit(EXIT_FAILURE);


第二,您需要开始注意readwrite返回的值,因为它们可能小于预期值。这些需要循环调用。

例如,对于read,您将使用以下内容:

// Returns the number of bytes read.
// EOF was reached if the number of bytes read is less than requested.
// On error, returns -1 and sets errno.
ssize_t read_fixed_amount(int fd, char *buf, size_t size) {
   if (size > SSIZE_MAX) {
      errno = EINVAL;
      return -1;
   }

   ssize_t bytes_read = 0;
   while (size > 0) {
      ssize_t rv = read(fd, buf, size); 
      if (rv <= 0)
         return rv;

      size -= rv;
      bytes_read += rv;
      buf += rv;
   }

   return bytes_read;
}

将使用类似这样的内容:

ssize_t bytes_read = read_fixed_amount(fd, buf, size);
if (bytes_read < 0) {
   perror("read");
   exit(EXIT_FAILURE);
}

if (bytes_read == 0) {
   printf("EOF reached\n");
   exit(EXIT_SUCCESS);
}

if (bytes_read != size) {
   fprintf(stderr, "read: Premature EOF.\n");
   exit(EXIT_FAILURE);
}

第三,只有在关闭管道写入端的所有文件描述符后,从管道读取的操作才会返回EOF。

在分叉之后,父母应该这样做

close(p1[0]); 
close(p2[0]);

在叉子之后,孩子1应该做

close(p1[1]);
close(p2[0]);
close(p2[1]);

在叉子之后,孩子2应该做

close(p1[0]); 
close(p1[1]);
close(p2[1]);

第四,这是怪物:

while (1) {
   dup2(p1[0], STDIN_FILENO);
   read(STDIN_FILENO, msgbuf, MSGSIZE); 
   ...
   close(p1[0]); 
   close(p1[1]);
}

真的吗?无限循环。尝试将STDIN重复设置为p1 [0]。复制封闭的描述符。

这应该出现在循环之前:

dup2(p1[0], STDIN_FILENO);
close(p1[0]);

或者您可以跳过这两个呼叫,而直接从p1[0]而不是STDIN_FILENO读取。

对于无限循环,它可以回到第二点。检查read返回的值。


第五,您只等待一个孩子完成,但是有两个孩子要等待。您需要致电wait两次。

答案 1 :(得分:0)

您需要向子进程发送一些信号,以通知然后终止,然后等待其退出。您应该定义一些预定义的消息,这意味着其终止子项的时间。检查以下代码。此处的预定义消息为"-1"。您应该选择与应用程序的真实数据不冲突的自己的数据。

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#define MSGSIZE 64

char msgbuf[MSGSIZE];

int main() {
  int p1[2];
  int p2[2];
  int nread;
  int choice = 0;
  pid_t child_a, child_b;
  if (pipe(p1) == -1) {
    printf("error in creating pipe\n");
    exit(-1);
  }

  if (pipe(p2) == -1) {
    printf("error in creating pipe\n");
    exit(-1);
  }

  child_a = fork();
  if (child_a == 0) {
    while (1) {
      dup2(p1[0], STDIN_FILENO);
      read(STDIN_FILENO, msgbuf, MSGSIZE);
      printf("%d receives message: %s\n", getpid(), msgbuf);
      close(p1[0]);
      close(p1[1]);
      if (strcmp(msgbuf, "-1") == 0) { // check if time to end
        break;
      }
    }
  } else {
    child_b = fork();
    if (child_b == 0) {
      while (1) {
        dup2(p2[0], STDIN_FILENO);
        read(STDIN_FILENO, msgbuf, MSGSIZE);
        printf("%d receives message: %s\n", getpid(), msgbuf);
        close(p2[0]);
        close(p2[1]);
        if (strcmp(msgbuf, "-1") == 0) {  // check if time to end
          break;
        }
      }
    } else {
      while (1) {
        printf("<child_to_receive_msg> <message>\n");
        scanf("%d %s", &choice, msgbuf);
        switch (choice) {
        case 1:
          usleep(250);
          write(p1[1], msgbuf, MSGSIZE);
          break;
        case 2:
          usleep(250);
          write(p2[1], msgbuf, MSGSIZE);
          break;
        default:
          printf("Process does not exist\n");
          break;
        case -1:
          strcpy(msgbuf, "-1");
          write(p1[1], msgbuf, MSGSIZE); // send message to end
          close(p1[0]);
          close(p2[0]);
          printf("parent waiting\n");
          wait(NULL);
          exit(0);
        }
      }
    }
  }
  return 0;
}