以下示例代码执行,但分叉进程的输出不可读:控制台上没有显示任何内容,直到我按Enter键,然后“读取失败!”示出。
问题是:为什么会这样,我如何与stdin
'ed过程中的stdout
和fork()
进行互动?
/* example1.c */
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
int main() {
pid_t pid = fork();
if (!pid) {
// child
char s[64];
printf("Enter something: ");
char *res = fgets(s, 64, stdin);
if (!res) {
printf("Read failed!\n");
} else {
printf("You entered: %s", s);
}
}
return 0;
}
更新
IO流的奇怪行为的另一个例子:
/* example2.c */
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
int main() {
pid_t pid = fork();
if (!pid) {
// child
char *argv[] = {
"-c",
"/home/user/echo.sh",
NULL
};
execv("/bin/sh", argv);
}
return 0;
}
echo.sh
脚本:
#!/bin/sh
read -p "Enter something: " INPUT
echo "You entered $INPUT"
这个返回
Enter something: /home/user/echo.sh: line 3: read: read error: 0: Input/output error
You entered
更新2:
看起来这段代码完全符合我们的要求:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
int main() {
pid_t pid = vfork();
if (!pid) {
// child
system("/home/user/echo.sh");
}
return 0;
}
解决方案是将fork
替换为vfork
。我只是不知道为什么这个工作......
答案 0 :(得分:2)
我想你想要wait(2)
。如在
/* example1.c */
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
int main() {
int status;
pid_t pid = fork();
if (!pid) {
// child
char s[64];
printf("Enter something: ");
char *res = fgets(s, 64, stdin);
if (!res) {
printf("Read failed!\n");
} else {
printf("You entered: %s", s);
}
}
else
{
while (wait(&status) != pid);
}
return 0;
}
答案 1 :(得分:1)
这是因为您的子进程现在位于孤立进程组中,其中没有进程是shell的直接子进程(谁应该进行作业控制)。
孤立进程组:至少没有成员的进程组,其中父级不在进程组中但在同一会话中(〜是直接的孩子的外壳)。
虽然父母和孩子都在跑,但情况是这样的:
$ ps fax -o pid,pgid,sid,ppid,tty,stat,time,cmd
27177 27177 27177 32170 pts/6 Ss 00:00:00 | \_ /bin/bash
4706 4706 27177 27177 pts/6 S+ 00:00:00 | \_ ./ex1
4707 4706 27177 4706 pts/6 S+ 00:00:00 | \_ ./ex1
进程组4706上有两个进程4706和4707. 4706是27177的子进程,它位于同一个会话(27177)中,但进程组不同(27177):它是处理作业控制的shell进程组4706。
当父母去世时,情况如下:
$ ps fax -o pid,pgid,sid,ppid,tty,stat,time,cmd
27177 27177 27177 32170 pts/6 Ss+ 00:00:00 | \_ /bin/bash
4664 4663 27177 1 pts/6 S 00:00:00 ./ex1
进程组4663中只有一个进程4664,其父进程(init)不在同一会话中。 shell无法处理此流程组的作业控制,因此read()
和write()
获取EIO
。
答案 2 :(得分:0)
如果你在UNIX / Linux上,当stdout进入控制台时,它是行缓冲的。也就是说,在您执行任何操作之前,您看不到任何输出:
fflush(stdout)
prinf("\n")
当stdout到达其他地方(比如文件管道)时,它是完全缓冲的,即printf("\n")
不会刷新缓冲区。