2011-07-29 28 views
2

执行以下代码示例,但分叉进程的输出不可读:控制台上没有显示任何内容,直到按Enter键,然后出现“Read failed!”显示。fork()'ed进程中的IO流

现在的问题是:为什么是这样的,我怎样才能与fork()编辑过程中的stdinstdout交互?

/* 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; 
} 

的解决方案是与vfork更换fork。我只是不知道为什么这个工作正常...

+0

也许是因为父母在孩子完成之前退出? – 2011-07-29 11:45:12

+0

@ 0A0D:谢谢,这似乎是这种情况,并且可以通过使用'system()'调用而不是'fork' /'execv'来轻松解决问题。但是,如何在继承IO流的单独进程中启动可执行文件?我的意思是,我需要能够随时杀死父进程,而不必等待孩子退出。 – Andy

+2

@Andy - 'vfork'暂停调用过程,直到孩子终止。这与在父进程中调用“wait”完全相同。 – Seth

回答

0

如果你在UNIX/Linux上,当stdout进入控制台时,它是行缓冲的。也就是说,你看不到任何输出,直到你可以:

  • fflush(stdout)
  • prinf("\n")
  • 标准输出缓冲区溢出。

当标准输出去别的地方(如文件的管道)是全缓冲,也就是printf("\n")不刷新缓冲区。

+0

那么,这并不能解决从stdin读取错误的问题。 – Andy

+0

第一步是在读取失败时检查'errno'中的错误代码。 –

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; 
} 
+0

它的工作原理,谢谢。但我需要的是在后台运行外部程序,而不用等待它完成。但是,正如@ 0A0D已经提到的那样,您的解决方案确实可以防止子流关闭,直到子进程结束。 – Andy

+0

或者,只需调用'_exit(0)'而不是'wait()'。 –

+0

@Maxim:不能这样做:可能有很多其他代码在fork()和ing之间执行,所以调用'_exit',它不处理很多''exit “确实,似乎不可能。 – Andy

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和4707上的进程组4706 4706 27177的一个孩子,这是在同一会话(27177),但是不同的进程组(27177):它是处理进程组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 

只有一个过程,4664,过程组4663,和它的父(INIT)是不是在同一个会话。 shell不能处理该进程组的作业控制,因此,read()write()得到EIO