发送后台进程到前台
我的一个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并改变一些信号?
我在这里看到一些错误。
- 你永远不会把子进程放在它自己的进程组中;因此,它仍保留在原来的一个中,因此在前景中连同其父。
- 您打给
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()
。
前景?背景?你什么意思? – texasbruce 2014-09-06 03:18:36
为什么你需要'fork'?看起来你只有一个流程实际上在做任何事情;你可以直接'execl'而不分叉。 。 。 – ruakh 2014-09-06 03:27:17
@ruakh这个程序只是真实程序中的一个子进程的大纲 - 子进程最终会删除父进程的可执行程序。 – Kartoffelpelz 2014-09-06 10:19:30