关于在我的虚拟 shell 中使用 fork() 的后台进程和子进程

问题描述 投票:0回答:2

我正在尝试用 C 创建一个简单的 shell 程序。我需要它做的是向用户提供一个提示,让他们可以运行其他本地程序。我可以使用 fork() 来很好地完成这一部分,其中父进程 wait() 在子进程上,而子进程 execvp() 是程序。

但是,如果“&”字符附加到用户命令的末尾,我需要他们的程序在后台运行,这意味着我需要父进程不等待子进程,而是立即将提示返回给用户,同时允许后台进程继续运行,但不允许其在屏幕上显示任何内容。我只是想能够通过 ps 命令检查它是否仍然存在。

我尝试理解使用 fork() 创建子进程背后的想法,然后再次让子进程 fork() 创建孙子进程,然后立即 exit() 子进程。即,孤儿孙子。据说这允许父级仍然等待子级,但是由于子级几乎立即结束,所以好像它根本不等待?有什么关于僵尸疯狂的事吗?我不知道。我遇到的几个网站似乎都推荐将此作为在后台运行进程的方法。

但是,当我尝试这样做时,程序流程中发生了一些疯狂的事情,“后台”进程继续在屏幕上显示输入,我真的不知道从这里该去哪里。

这是我对代码的实现,我确信这是完全错误的。我只是想知道这整个孙子的事情是否是我需要采取的路线,如果是这样,我的代码有什么问题吗?

36 int main(int argc, char *argv[])
37 {
38     char buffer[512];
39     char *args[16];
40     int background;
41     int *status;
42     size_t arg_ct;
43     pid_t pid;
44 
45     while(1)
46     {
47         printf("> ");
48         fgets(buffer, 512, stdin);
49         parse_args(buffer, args, 16, &arg_ct);
50 
51         if (arg_ct == 0) continue;
52 
53         if (!strcmp(args[0], "exit"))
54         {
55             exit(0);
56         }
57 
58         pid = fork();  //here I fork and create a child process
61 
62         if (pid && !background)  //i.e. if it's the parent process and don't need to run in the background (this is the part that seems to work)
63         {
64             printf("Waiting on child (%d).\n", pid);
65             pid = wait(status);
66             printf("Child (%d) finished.\n", pid);
67         }
68         else
69         {
70             if (background && pid == 0) { //if it's a child process and i need to run the command in background
71                
72                 pid = fork(); //fork child and create a grandchild
73                 if (pid) exit(0); //exit child and orphan grandchild
74                 
75                 execvp(args[0], args); //orphan execs the command then exits
76                 exit(1);
77 
78             } else exit(0);
79         }
80     }
81     return 0;
82 }

P.S. 需要明确的是,我需要在后台运行的进程不再发出声音,即使它有一个无限循环的打印语句或其他东西。我只是想确保它仍然通过 ps -a 或其他方式在后台运行。

抱歉,我的解释令人困惑,我只是不知道如何更好地解释它。

提前致谢

P.P.S我将实现它,以便每个后续命令都将确定“背景”的布尔值,抱歉造成混乱

c unix fork grandchild
2个回答
34
投票

您不想在 shell 中使用 double-

fork()
方法 - 这是为了编写专门想要逃避运行它们的 shell 监督的守护进程。

相反,在现有 shell 中复制

&
行为的方法是调用
fork()
,然后在子进程中调用
setpgid(0, 0);
将子进程放入新的 进程组。父级只是继续(也许在打印子级的
PID
之后) - 它不会调用
wait()

每个终端只能有一个前台进程组,即当前允许向终端发送输出的进程组。这将仍然是您的 shell 所属的进程组,因此您的 shell 将保留在前台。

如果后台进程组尝试从终端读取数据,则会向其发送信号来停止它。仍然允许输出到终端 - 这是正常的(在常规 shell 中尝试

ls &
)。要在 shell 中实现
fg
命令,您将需要
tcsetpgrp()
函数来更改前台进程组。

您还需要定期使用

waitpid()
选项调用
WNOHANG
- 例如,在显示 shell 提示符之前立即调用。这将允许您检测后台进程何时退出或停止(或者,您可以处理
SIGCHLD
信号)。


0
投票

尝试 dup2 将 stdout 重定向到 /dev/null。

© www.soinside.com 2019 - 2024. All rights reserved.