The followin开发者_Go百科g example code executes, but output from the forked process is not readable: nothing is shown on console until I press enter, and then "Read failed!" shows.
The question is: why is that, and how can I interact with stdin
and stdout
from the fork()
'ed process?
/* 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;
}
Update:
Another example of strange behavior of IO streams:
/* 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
script:
#!/bin/sh
read -p "Enter something: " INPUT
echo "You entered $INPUT"
This one returns
Enter something: /home/user/echo.sh: line 3: read: read error: 0: Input/output error
You entered
Update 2:
Looks like this code does exactly what's needed:
#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;
}
The solution was to replace fork
with vfork
. I just don't know why is this one working...
I think you want wait(2)
. As in
/* 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;
}
This is because your child process is now in an orphaned process group, where no process is a direct child of the shell (who is supposed to do job-control).
Orphaned process group: Process group which doesn't have at least a member who has a parent not in the process group but within the same session (~ is a direct child of the shell).
While the parent and child are both running, the situation is like this:
$ 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
There are two processes, 4706 and 4707 on process group 4706. 4706 is a child of 27177, which is in the same session (27177), but different process group (27177): it's the shell that deals with job control for process group 4706.
When the parent dies, the situation is like this:
$ 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
There is only one process, 4664, in process group 4663, and its parent (init) isn't on the same session. The shell cannot deal with job control for this process group, therefore, read()
and write()
get EIO
.
If you are on UNIX/Linux, when stdout goes into console it is line-buffered. That is, you don't see any output until you do either:
fflush(stdout)
prinf("\n")
- stdout buffer overflows.
When stdout goes somewhere else (like pipe of file) it is fully-buffered, that is, printf("\n")
does not flush the buffer.
精彩评论