我正在编写一些涉及管道使用的C代码。为了使子进程使用我的管道而不是STDOUT进行输出,我使用了以下几行:
close(STDOUT);
dup2(leftup[1], STDOUT);
然而,它似乎进入某种无限循环或挂在那些线上。当我摆脱close
时,它会挂在dup2
上。
奇怪的是,同样的想法适用于STDIN的前一行:
close(STDIN);
dup2(leftdown[0], STDIN);
可能导致此行为的原因是什么?
编辑:只是为了清楚......
#define STDIN 0
#define STDOUT 1
编辑2:这是一个精简的例子:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#define STDIN 0
#define STDOUT 1
main(){
pid_t child1 = 0;
int leftdown[2];
if (pipe(leftdown) != 0)
printf("ERROR");
int leftup[2];
if (pipe(leftup) != 0)
printf("ERROR");
printf("MADE PIPES");
child1 = fork();
if (child1 == 0){
close(STDOUT);
printf("TEST 1");
dup2(leftup[1], STDOUT);
printf("TEST 2");
exit(0);
}
return(0);
}
永远不会到达"TEST 1"
行。唯一的输出是"MADE PIPES"
。
答案 0 :(得分:1)
在最小值处,您应该确保dup2
函数返回新文件描述符而不是-1
。
总有可能会出现错误(例如,如果之前pipe()
调用失败)。此外,绝对肯定你正在使用正确的索引(0和1) - 我之前一直被它咬过,这取决于你是在父进程还是子进程。
根据您的编辑,MADE PIPES
是打印的最后一件事我并不感到惊讶。
当您尝试打印TEST 1
时,您已经关闭了STDOUT
描述符,以便无处可去。
当您尝试打印TEST 2
时,您dup
编辑了STDOUT
描述符,以便转到父级,但您的父级不会读取它。
如果您将分叉代码更改为:
child1 = fork();
if (child1 == 0){
int count;
close(STDOUT);
count = printf("TEST 1\n");
dup2(leftup[1], STDOUT);
printf("TEST 2 (%d)\n", count);
exit(0);
} else {
char buff[80];
read (leftup[0], buff, 80);
printf ("%s\n", buff);
sleep (2);
}
您将看到父项输出TEST 2 (-1)
行,因为它通过管道读取它。关闭-1
描述符后(但在printf
编辑之前),STDOUT
中的dup
返回代码,这意味着它失败。
来自ISO C11 7.20.6.3 The printf function
:
printf
函数返回传输的字符数,如果发生输出或编码错误,则返回负值。
答案 1 :(得分:1)
多重要提,
当您使用fork时,它几乎会导致父进程的完整副本。这也包括为stdout
标准输出流设置的缓冲区。 stdout
流将保存数据,直到缓冲区已满或明确请求从缓冲区/流中刷新数据。因此,现在你有"MADE PIPES"
坐在缓冲区。当您关闭STDOUT
fd并使用printf
将数据写入终端时,它只会将您的"TEST 1"
和"TEST 2"
转移到stdout
缓冲区中不会导致任何错误或崩溃(由于足够的缓冲区)。因此,即使在pipe
上复制STDOUT
fd后,由于缓冲输出printf
甚至没有触及管道写入结束。最重要的是,请仅使用一组API,即* NIX或标准C lib函数。确保你很好地理解这些库,因为它们经常用于某种优化。
现在,另外要提一下,确保在适当的过程中关闭管道的适当末端。这意味着,如果使用pipe-1用于从父级到子级进行通信,那么请确保在父级中关闭读取端并在子级中写入end。否则,您的程序可能会挂起,由于与文件描述符关联的引用计数,您可能认为在子级中关闭读取结束意味着管道读取结束已关闭。但是当你没有在父级中关闭读取结束时,那么对于管道的读取结束你有额外的引用计数,并且最终管道永远不会关闭。
关于你的编码风格还有很多其他的事情,你应该抓住它:) 你越早学会它就能节省你的时间。 :)
错误检查绝对重要,至少使用assert来确保您的假设是正确的。
使用printf
语句记录错误或作为调试方法,并且您正在更改终端FD的(STDOUT / STDIN / STDERR)
,更好地打开日志文件*NIX
打开并写入错误/日志条目。
最后,使用strace
实用程序对您有很大帮助。该实用程序将允许您跟踪执行代码时执行的系统调用。它非常简单直接。如果您具有正确的权限,您甚至可以将其附加到执行进程。