将后台进程发送到前台

send background process to foreground

本文关键字:前台 后台进程      更新时间:2023-10-16

我的一个c++程序调用fork(),子程序立即执行另一个程序。我必须放置与子项的交互,但同时终止其父项,因为它的可执行文件将被替换。我需要以某种方式将孤儿放回前台,这样我就可以通过bash与它进行交互——我目前只得到它的输出。因此,我要么需要将父级发送到后台,将子级发送到前台,然后终止父级,要么在父级终止时立即将子级发到后台。

据我所知,在父进程终止之前,我必须将子进程设置为进程组组长。通过大量借用这个线程,我到达了以下测试场(注意,这不是完整的程序-它只是概述了过程):

int main(int argc, char *argcv[])
printf("%in", argc);
printf("nhello, I am %in", getpid());
printf("parent is %in", getppid());
printf("process leader is %in", getsid(getpid()));
int pgrp;
std::stringstream pidstream;
pidstream << tcgetpgrp(STDIN_FILENO);
pidstream >> pgrp;
printf("foreground process group ID %in", pgrp);
if(argc==1)
{
    int child = fork();
    if(!child) {execl("./nameofthisprogram","nameofthisprogram", "foo", NULL);}
    else
    {
        signal(SIGTTOU, SIG_IGN);
        usleep(1000*1000*1);
        tcsetpgrp(0, child);
        tcsetpgrp(1, child);
        std::stringstream pidstream2;
        pidstream2 << tcgetpgrp(STDIN_FILENO);
        pidstream2 >> pgrp;
        printf("foreground process group ID %in", pgrp);
        usleep(1000*1000*3);
        return 0;           
    }
}
// signal(SIGTTOU, SIG_IGN); unnecessary
int input;
int input2;
printf("write somethingn");
std::cin >> input;
printf("%in", input);
usleep(1000*1000*3);
printf("%in", input);
printf("write something elsen");
std::cin >> input2;
usleep(1000*1000*3);
printf("%in", input2);
return 0;

使用上面的代码,在我得到第一个输入的提示后,父级就死了。如果我将答案延迟到父母去世之后,它会拾取第一个输入字符并再次打印。对于input2,程序不等待我的输入。因此,似乎在第一个字符之后,输入就完全终止了。我处理这个问题是根本错误的,还是仅仅是重新分配几个id并改变一些信号的问题?

我发现这里有一些错误。

  1. 您永远不会将子进程放在自己的进程组中;因此,它保留在原始的中,因此与父级一起处于前台
  2. 您正在呼叫tcsetpgrp()两次;它只需要调用一次。假设没有重定向,stdin和stdout都引用终端,因此任何一个调用都可以

使用上面的代码,在我得到第一个输入的提示后,父级就死了。如果我将答案延迟到父母去世之后,它会拾取第一个输入字符并再次打印。对于input2,程序不等待我的输入。因此,似乎在第一个字符之后,输入就完全终止了。

您在这里观察到的是1.的直接结果:由于两个进程都在前台,所以它们都在争相从stdin读取,结果是未定义的。

我需要以某种方式将孤儿放回前台,这样我就可以通过bash与它进行交互——我目前只得到它的输出。

据我所知,您可能希望在fork()/exec()之后与execute的子级进行交互。要做到这一点,子进程需要在自己的进程组中,并且需要放在前台。

int child = fork();
signal(SIGTTOU, SIG_IGN);
if (!child) {
  setpgid(0, 0); // Put in its own process group
  tcsetpgrp(0, getpgrp()); // Avoid race condition where exec'd program would still be in the background and would try to read from the terminal
  execl("./nameofthisprogram","nameofthisprogram", "foo", NULL);
} else {
  setpgid(child, child); // Either setpgid call will succeed, depending on how the processes are scheduled.
  tcsetpgrp(0, child); // Move child to foreground
}

请注意,我们在父对象和子对象中都调用setpgid()/tcsetpgrp()对。我们这样做是因为我们不知道哪个将首先被调度,并且我们希望避免竞争条件,在这种情况下,exec’ed程序将在父级有时间将其放在前台之前尝试从stdin读取(因此接收到一个SIGTTIN,该SIGTTIN将停止进程)。我们也忽略SIGTTOU,因为我们知道子级或父级将接收到一个带有对tcsetpgrp()的调用的SIGTTOU。