我在C编写一个简单的linux shell。
有时候当使用fork然后执行NON-BLOCKING命令时 - 我的下一个printf
消失了。我猜这是因为子进程正在写入stdout。
如果我使用waitpid
没有问题 - 因为我的下一个printf只会在子进程终止后打印。有时用户会想要执行非阻塞命令 - 然后我不会使用waitpid
- 然后我的下一个printf
将会消失。
如果我使用sleep(1)
,它也可以解决问题。但我想知道是否有一种更优雅的方式来实现这一目标。
int main( int argc, char *argv[], char *env[] )
{
pid_t child_pid;
int status;
if((child_pid = fork()) < 0 )
{
perror("fork failure");
exit(1);
}
if(child_pid == 0)
{
printf("\nChild: I am a new-born process!\n\n");
char *sd[] = {"ls", "-l", NULL};
execvp(sd[0], sd);
}
else
{
printf("THIS LINE SOMETIMES DISAPPEAR");
}
return 0;
}
答案 0 :(得分:0)
通常,当您希望它返回输出时,您可以为子项设置显式IO管道。当你分叉并执行子进程时,它将继承父进程的文件描述符。所以你想通过调用pipe(2)为孩子的输出创建一个单向管道。在子项中,在执行命令之前,将标准输出和标准错误重定向到管道的写入端(使用dup2(2))。在父级中,您只需从管道的读取端读取,直到EOF并对输出执行任何操作。然后你等孩子退出。
这是一个没有任何错误处理的例子:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int
main(int argc, char *argv[])
{
pid_t child;
int p[2], to_parent, from_child;
int child_status;
char buffer[1024];
ssize_t nread;
/* create a unidirectional pipe
* - child process will write to p[0]
* - parent process will read from p[1]
*/
pipe(p);
from_child = p[0];
to_parent = p[1];
child = fork();
if (child == 0) {
/* child */
/* close parent end of pipe */
close(from_child);
/* close unnecessary file descriptors */
close(STDIN_FILENO);
/* redirect standard output & error to pipe */
dup2(STDOUT_FILENO, to_parent);
dup2(STDERR_FILENO, to_parent);
/* exec or die */
execlp("ls", "ls", "-l", NULL);
exit(EXIT_FAILURE);
}
/* parent */
/* close child end of pipe */
close(to_parent);
/* read output from child until EOF */
while ((nread=read(from_child, &buffer[0], sizeof(buffer))) > 0) {
write(STDOUT_FILENO, &buffer[0], nread);
}
buffer[0] = '\n';
write(STDOUT_FILENO, &buffer[0], 1);
close(from_child);
/* wait for child */
wait(&child_status); /*mindlessly copied from stack overflow*/
if (WIFEXITED(child_status)) {
printf("child %lu exited with code %d\n",
(unsigned long)child, WEXITSTATUS(child_status));
} else if (WIFSIGNALED(child_status)) {
printf("child %lu terminated due to signal #%d%s\n",
(unsigned long)child, WTERMSIG(child_status),
WCOREDUMP(child_status) ? ", core dumped" : "");
} else if (WIFSTOPPED(child_status)) {
printf("child %lu stopped due to signal #%d\n",
(unsigned long)child, WSTOPSIG(child_status));
}
return 0;
}
关闭不必要的文件描述符时必须要小心。例如,将管道的to_parent
侧打开将导致父母的读取永远不会返回EOF。