简体   繁体   English

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

[英]Regarding background processes using fork() and child processes in my dummy shell

I'm trying to create a simple shell program in C. What I need it to do is provide the user with a prompt in which they can run other local programs. 我正在尝试在C中创建一个简单的shell程序。我需要它做的是为用户提供一个可以运行其他本地程序的提示。 I can do that part fine, using a fork() in which the parent process waits() on the child,and the child execvp()'s the program. 我可以使用fork()来完成该部分,其中父进程在子进程上等待(),而子进程execvp()是程序。

However, if the '&' character is appended to the end of the user's command, I need their program to run in the background, meaning I need the parent to NOT wait on the child process but instead immediately return the prompt to the user, while allowing the background process to continue to run, but not allowing it to display anything on the screen. 但是,如果'&'字符附加到用户命令的末尾,我需要他们的程序在后台运行,这意味着我需要父进程不等待子进程,而是立即将提示返回给用户,同时允许后台进程继续运行,但不允许它在屏幕上显示任何内容。 I just want to be able to check that it still exists via ps command. 我只是想通过ps命令检查它是否仍然存在。

I tried to understand the idea behind using fork() to create a child, then have the child fork() again to create a grandchild of sorts, then immediately exit()-ing the child process. 我试图理解使用fork()创建子项的想法,然后让子fork()再次创建一个类的孙子,然后立即退出() - 子进程。 ie, orphan the grandchild. 即,孤儿孙子。 Supposedly this allows the parent to still wait on the child, but since the child effectually ends almost immediately, it's like it doesn't wait at all? 据说,这允许父母仍然等待孩子,但由于孩子几乎立即有效地结束,它就像它不等待? Something about zombie madness? 关于僵尸疯狂的事情? I don't know. 我不知道。 Several sites I've come across seem to recommend this as a way to run a process in the background. 我遇到过的几个网站似乎都建议将其作为在后台运行流程的一种方式。

However, when I try to do this, I get wild things happening with the flow of the program, the 'background' process continues to display input on the screen, and I'm really not sure where to go from here. 但是,当我尝试这样做的时候,我发现程序流程发生了很多事情,“背景”过程继续在屏幕上显示输入,我真的不知道从哪里开始。

This is my implementation of the code, which I'm sure is quite wrong. 这是我对代码的实现,我确信这是非常错误的。 I'm just wondering if this whole grandchild thing is even the route I need to take,and if so, what's wrong with my code? 我只是想知道这整个孙子的事情是否是我需要采取的路线,如果是这样,我的代码有什么问题?

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 }

PS To be clear, I need the process that I'm running in the background to never make a sound again, even if it's got an infinite loop of print statements or something. PS为了清楚起见,我需要我在后台运行的过程永远不会再发出声音,即使它有无限循环的打印语句或其他东西。 I just want to make sure that it is still running in the background via ps -a or something. 我只想确保它仍然通过ps -a或其他东西在后台运行。

Sorry for the confusing explanation I just don't know how to explain it any better. 很抱歉这个令人困惑的解释我只是不知道如何更好地解释它。

Thanks in advance 提前致谢

PPS I'll be implementing it so that each subsequent command will determine the boolean value of 'background', sorry for the confusion PPS我将实现它,以便每个后续命令将确定'背景'的布尔值,抱歉混淆

You do not want to use the double- fork() method in a shell - that is for writing daemons that specifically want to escape from supervision by the shell that ran them. 您不希望在shell中使用double- fork()方法 - 用于编写特别希望逃避运行它们的shell监视的守护进程。

Instead, the way to duplicate the behaviour of & in existing shells is to call fork() , then in the child call setpgid(0, 0); 相反,复制现有shell中&的行为的方法是调用fork() ,然后在子调用setpgid(0, 0); to put the child into a new process group . 将孩子带入一个新的流程组 The parent just continues on (perhaps after printing the PID of the child) - it doesn't call wait() . 父母只是继续(也许在打印孩子的PID之后) - 它不会调用wait()

Each terminal can have only one foreground process group, which is the process group which is currently allowed to send output to the terminal. 每个终端只能有一个前台进程组,这是当前允许向终端发送输出的进程组。 This will remain the process group of which your shell is a member, so your shell will remain in the foreground. 这将保留您的shell所属的进程组,因此您的shell将保留在前台。

If a background process group tries to read from the terminal, it will be sent a signal to stop it. 如果后台进程组尝试从终端读取,则会向其发送一个信号以阻止它。 Output to the terminal is still allowed - this is normal (try ls & in your regular shell). 仍然允许输出到终端 - 这是正常的(尝试ls &在您的常规shell中)。 To implement the fg command in your shell, you will need the tcsetpgrp() function to change the foreground process group. 要在shell中实现fg命令,您需要使用tcsetpgrp()函数来更改前台进程组。

You will also want to call waitpid() with the WNOHANG option regularly - say, immediately before you display the shell prompt. 您还需要定期调用带有WNOHANG选项的waitpid() - 例如,在显示shell提示符之前。 This will allow you to detect when the background process has exited or stopped (or alternatively, you can handle the SIGCHLD signal). 这将允许您检测后台进程何时退出或停止(或者您可以处理SIGCHLD信号)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM