c - 管道不适用于信号量

标签 c pipe semaphore

我想在 3 个子进程之间创建两个管道,但我首先想让第一个管道 pipe1 在两个 fork 进程之间工作。问题是,当我从第一个进程复制标准输出并同样从另一个进程复制标准输入时,我没有得到输出。

int main()
{
  int pipe1[2];
  int pipe2[2];
  pipe(pipe1);
  pipe(pipe2);
  sem_t mutex_pipe1;
  sem_t mutex_pipe2;
  sem_init(&mutex_pipe1, 0, 0);
  sem_init(&mutex_pipe2, 0, 1);


  if (fork()==0) {           //process 1
    close(1);        /* close normal stdout */
    dup(pipe1[1]);   /* make stdout same as pfds[1] */
    sem_post(&mutex_pipe1);
    execlp("ls", "ls", NULL);       
  }

  if (fork()==0){           //process 2
    sem_wait(&mutex_pipe1);
    close(0);
    dup(pipe1[0]);
    dup2(pipe1[1], 1)      //want to open stdout again.
    sem_post(&mutex_pipe1);
    execlp("wc", "wc", "-l", NULL);           
  }

最佳答案

在您提供的代码中,您的信号量没有为您做任何有用的事情。我不清楚您甚至认为它们会做什么,尤其是当您的子进程调用 exec()-family 函数时。

此外,一旦关闭,您将无法“再次打开 stdout”。您可以将文件描述符 1(以及 stdout)与不同的文件相关联,但是一旦您关闭了与其关联的所有 FD,就无法取回该文件,open()< 除外ing 或 fopen() 再次调用它。

但是,您似乎没有意识到在 fork() 之后,子进程和父进程不共享内存,至少在一个人写入的普通内存对子进程可见的意义上是这样。其他。因此,在您的原始代码中,当第一个 child 关闭其 stdout 时,父级不受影响,第二个 child 不继承任何更改或任何需要恢复原始 stdout.

另一方面,请注意,当您fork() 一个子进程时,它会继承父进程打开的文件描述符,这会导致两个进程打开每个文件描述符。此外,当您复制一个 FD 时,您会在同一个文件上打开第二个 FD。您需要在关闭底层打开的文件之前关闭它们中的所有,否则可能会产生不良影响。特别是在您的情况下,您的第二个子进程挂起,因为它正在等待其 stdin 在另一侧关闭,尽管第一个子进程关闭了它的副本,父进程仍然持有一个打开的 FD。 wc 程序在消耗完所有输入之前不会产生任何输出。如果您改为执行,例如 cat,您可能会看到一些输出。

此外,父进程通常应该等待其子进程完成后再退出,如果它继续执行其他工作,它最终必须等待它们在它们之后清理。

最后,总是,总是检查错误代码的返回值。

这是一个非常简单的版本,说明如何设置一对通过管道进行单向通信的子进程:

#define DIE do { perror(NULL); exit(1); } while (0)
#define DO_OR_DIE(f) do { if ((f) < 0) DIE; } while (0)

int main(void)
{
  int pipe1[2];

  DO_OR_DIE(pipe(pipe1));

  switch (fork()) {
      case -1:  /* failed to fork */
          DIE;
      case 0:   /* child process 1 */
          /* make stdout a copy of the write end of the pipe */
          DO_OR_DIE(dup2(pipe1[1], STDOUT_FILENO));
          /* close the excess file descriptor */
          DO_OR_DIE(close(pipe1[1]));
          execlp("ls", "ls", NULL);
          /* execlp returns only on failure */
          DIE;
      /* default: parent process */
  }

  /* close the parent's copy of this FD, lest child2 hang */
  DO_OR_DIE(close(pipe1[1]));

  switch (fork()) {
      case -1:  /* failed to fork */
          DIE;
      case 0:   /* child process 1 */
          /* make stdout a copy of the write end of the pipe */
          DO_OR_DIE(dup2(pipe1[0], STDIN_FILENO));
          /* close the excess file descriptor */
          DO_OR_DIE(close(pipe1[0]));
          execlp("wc", "wc", "-l", NULL);           
          /* execlp returns only on failure */
          DIE;
      /* default: parent process */
  }

  /* close the parent's copy of this FD, for consistency and tidiness*/
  DO_OR_DIE(close(pipe1[0]));

  /* wait for two child processes to stop */
  DO_OR_DIE(wait(NULL));
  DO_OR_DIE(wait(NULL));

  return 0;
}

关于c - 管道不适用于信号量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29627195/

相关文章:

c - 从二进制文件读取并转换为 double ?

c - 为什么#pragma 不适用于 ideone?

c - CUDA 上的二维数组

go - 运行时/cgo : pthread_create failed: Resource temporarily unavailable

c - 为信号量定义变量

c - 将 csv 文件读取到结构时出错

对 Unix 中 exec(family) 的使用感到困惑

c - 使用 Pipe()、fork() 和信号处理来管理程序中的内存和管道/套接字

c - 多线程 printf() 与 c 中的信号量

c++ - 调用 xSemaphoreGive 后,xSemaphoreTake 不会恢复任务