我不是英语用户,所以可能会有一些错误的句子:)
我正在制作迷你贝壳。在代码中,子进程运行execvp函数。父进程将子进程的pgid更改为与子进程的pid相同。
但是,更改child的pgid后,child开始在后台运行,因此minishell不能正常工作。如果我不更改child的pgid,那么它就可以正常工作。
我想知道如何将后台子进程带到前台,或者如何不让子进程在后台运行。
int execute(){
pid_t pid = fork();
if (pid == 0){
execvp(args[idx], &args[idx]);
}
else{
setpgid(pid, pid);
int status;
waitpid(pid, &status, WUNTRACED);
if (WIFSTOPPED(status))
kill(pid, SIGINT);
}
}
TL;DR:使用tcsetpgrp()
在相关终端上更改前台进程组
在任何给定时间,终端最多有一个控制进程组。该进程组中的进程可以接收来自终端的输入并将输出写入终端,它们还可以接收终端驱动程序响应ctrl-C等按键所产生的某些信号。处于其控制终端的控制进程组中意味着进程处于前台。
其他进程组中的进程不接收来自终端的输入,也不能向终端写入输出。与控制进程组中的进程相比,在不同的情况下,它们将从终端驱动程序接收不同的信号。这就是在后台的意思。
一个执行作业控制的shell,它包括但不限于管理其他进程的前台和后台状态,它通过将它生成的进程分配给适当的进程组(setpgid()
)并管理在任何给定时间哪个进程组(包括它自己的进程组)是前台进程组(tcsetpgrp()
)来实现这一点。这比在单独的进程组中运行所有作业要复杂得多。
Glibc手册包含了很多关于这方面的信息,包括示例代码。考虑阅读作业控制一章,特别是其中的实现作业控制Shell一节。