2014-09-06 100 views
1

我的一个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

前景?背景?你什么意思? – texasbruce 2014-09-06 03:18:36

+2

为什么你需要'fork'?看起来你只有一个流程实际上在做任何事情;你可以直接'execl'而不分叉。 。 。 – ruakh 2014-09-06 03:27:17

+0

@ruakh这个程序只是真实程序中的一个子进程的大纲 - 子进程最终会删除父进程的可执行程序。 – Kartoffelpelz 2014-09-06 10:19:30

回答

0

我在这里看到一些错误。

  1. 你永远不会把子进程放在它自己的进程组中;因此,它仍保留在原来的一个中,因此在前景中连同其父
  2. 您打给tcsetpgrp()两次;它只需要被调用一次。假设没有重定向,stdin和stdout都指向终端,因此任何一个调用都可以。

通过上面的代码,在获得第一个输入提示后,父项将死亡。如果我在超出父母死亡的时候推迟了我的答案,它会拾取第一个输入字符并再次打印。对于input2,程序不会等待我的输入。所以看起来,在第一个字符后,输入完全终止。

什么您看到的是这里是1.的直接后果:因为两个进程都在前台,他们都争着从标准输入读取和结果是不确定的。

我以某种方式需要得到孤儿回到前台,以便我可以通过bash与它交互 - 我目前只获得它的输出。

从我所了解的情况来看,你会期望与fork()/exec()之后的exec'ed孩子进行互动。要做到这一点,孩子需要在自己的过程组中,需要放在前台。

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()