将后台进程发送到前台

时间:2014-09-06 03:15:47

标签: c++ c linux bash

我的c ++程序调用fork(),子进程立即执行另一个程序。我必须与子进行交互,但同时终止其父进程,因为它的可执行文件将被替换。我不知何故需要让孤儿回到前台,以便我可以通过bash与它进行交互 - 我目前只得到它的输出。因此,我需要将父级发送到后台,将子级发送到前台,然后终止父级,或者在父级终止时立即将子级发送到后台。

据我所知,我必须在其父级终止之前将其设置为进程组组长。 通过this thread的慷慨借款,我到达了下面的测试场地(注意,这不是完整的程序 - 它只是概述了程序):

int main(int argc, char *argcv[])

printf("%i\n", argc);
printf("\nhello, I am %i\n", getpid());
printf("parent is %i\n", getppid());
printf("process leader is %i\n", getsid(getpid()));
int pgrp;
std::stringstream pidstream;
pidstream << tcgetpgrp(STDIN_FILENO);
pidstream >> pgrp;
printf("foreground process group ID %i\n", 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 %i\n", pgrp);
        usleep(1000*1000*3);
        return 0;           
    }
}
// signal(SIGTTOU, SIG_IGN); unnecessary

int input;
int input2;

printf("write something\n");
std::cin >> input;
printf("%i\n", input);
usleep(1000*1000*3);
printf("%i\n", input);

printf("write something else\n");
std::cin >> input2;
usleep(1000*1000*3);
printf("%i\n", input2);

return 0;

使用上面的代码,在提示输入第一个输入后,父级会死掉。如果我将我的答案推迟到父母的死亡之后,它会拿起第一个输入字符并再次打印出来。对于input2,程序不等待我的输入。 因此,似乎在第一个字符之后,输入完全终止。 我是否接近这个根本错误,或者只是重新分配一些更多的ID并改变一些信号?

1 个答案:

答案 0 :(得分:0)

我在这里看到了一些错误。

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

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

    你在这里观察到的是1.的直接结果:由于两个进程都处于前台,因此它们都在竞争从stdin读取并且结果未定义。

      

    我不知何故需要让孤儿回到前台,以便我可以通过bash与它进行交互 - 我目前只得到它的输出。

    根据我的理解,你会期望在fork()/exec()之后与执行的孩子互动。要做到这一点,孩子需要在自己的进程组中,并且需要放在前台。

    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)有时间把它放在前台。我们也忽略SIGTTOU,因为我们知道孩子或父母将收到一个调用tcsetpgrp()的人。