我想知道一种干净优雅的方法来执行以下操作:假设我编写了一个名为 的 C++ 程序,foo
作为名为 的 shell 脚本的一部分在内部运行bar.sh
。我想让 shell 脚本foo
作为后台进程运行,然后等待直到执行foo
到达我选择的一行,此时bar
应继续执行。
为了清楚起见,这里有一个虚拟示例bar.sh
:
#!/bin/bash
./foo
wait
echo "WAKING UP"
这是foo
:
#include <iostream>
int main(){
for (int i = 0; i < 1000000; i++){
std::cout << i << std::endl;
if (i == 50){
//Wake up bash!
}
}
}
我想修改foo
和/或bar
以便等待命令将在迭代 50bar
时停止。foo
因此,当 for 循环到达 时foo
,i = 50
应该bar
唤醒并打印 WAKING UP。当然也foo
可以继续保持运行。
我该如何修改这些程序才能达到这种效果?
答案1
fork()
这基本上就是+的目的setsid()
。
酒吧.sh
#!/bin/bash
echo "Launching foo"
./foo
echo "Waking up"
foo.c
#include <stdio.h>
#include <unistd.h>
int main(int ac, char ** av)
{
int pid;
for (int i=0; i<5; i++) {
sleep(1);
}
printf("OK, we count to 5.\n");
/*
* Here we fork() + setsid() to detach from parent process
* Return value of fork is 0 if you are in child, pid of the child
* if you're in the parent process
*/
pid = fork();
if (pid == 0) {
setsid();
printf("We forked, still running but shell may be back\n");
sleep(5);
printf("Exiting ...\n");
} else {
return 0;
}
}
结果
/tmp/pouet$ ps aux|grep foo
me 8595 0.5 0.1 217548 18576 pts/12 T 14:17 0:01 vim foo.c
me 9167 0.0 0.0 12716 912 pts/12 S+ 14:21 0:00 grep foo
/tmp/pouet$ ./bar.sh
Launching foo
OK, we count to 5.
We forked, still running but shell may be back
Waking up
/tmp/pouet$ ps aux|grep foo
me 8595 0.5 0.1 217548 18576 pts/12 T 14:17 0:01 vim foo.c
me 9189 0.0 0.0 4160 76 ? Ss 14:21 0:00 ./foo
me 9192 0.0 0.0 12716 940 pts/12 S+ 14:21 0:00 grep foo
/tmp/pouet$ Exiting ...
/tmp/pouet$ ps aux|grep foo
me 8595 0.5 0.1 217548 18576 pts/12 T 14:17 0:01 vim foo.c
me 9212 0.0 0.0 12716 908 pts/12 S+ 14:21 0:00 grep foo
答案2
一种方法是先fork
离开父母。
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
int main(){
for (int i = 0; i < 1000000; i++){
std::cout << i << std::endl;
if (i == 50){
if (fork() != 0) {
_Exit(0);
}
}
}
}
这可能会产生不良影响,使用_Exit
is 可以避免最明显的影响。
另一种方法是 C++ 程序向父程序发送信号。这也会终止内置的等待(我不记得它是 POSIX 还是只是一个 bashism)。
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
int main(){
for (int i = 0; i < 1000000; i++){
std::cout << i << std::endl;
if (i == 50){
kill(getppid(), SIGINT);
}
}
}
这里需要注意的一件事是脚本和C++程序之间的过程。您可能想寻找trap
一种在 shell 脚本中处理信号的方法。