在树莓派(最近的树莓派)上,我编写了一个应用程序,根据网络请求的需要,生成一个应用程序,并根据不同的网络请求的需要,杀死它。生成机制就是fork/exec。杀死是通过kill(childPid, SIGQUIT)完成的。正如您想象的那样,它是一个简单的 C++ 代码,并且运行良好。
也就是说,它工作正常,除非我从 /etc/rc.local 启动它。从那里启动它的命令只是一个适当的 cd,然后
./effectPlayer &
它启动良好,接收请求良好,生成良好(它跨越一个 aplay,因此判断它何时工作很简单),但完全无法根据请求终止 aplay 子进程。它像平常一样调用kill(),并且kill()返回0。但是aplay仍在继续。
我认为这是一些奇怪的事实,因为从 /etc/rc.local 生成它会在 fork 或 Kill 中赋予它一些特殊的行为,但我不明白是什么。我缺少什么?
编辑:添加问题的答案。打开日志记录从 /etc/rc.local 运行,应用程序报告:
23:10:06 10-11-2019 (effectPlayer) 7: P1 64 elvenHall #command to start playing
23:10:06 10-11-2019 (sound) launched 1083: /usr/bin/aplay -q -... #what it forks/execs
23:10:10 10-11-2019 (effectPlayer) 7: X1000 #command to stop playing
23:10:10 10-11-2019 (sound) sending 3 to 1083, result 0 0 #what kill() is asked to do
翻译后,它被要求播放特定的效果并生成一个 aplay 来处理它。它起作用了(我听到音频),然后我发送命令停止所有播放。它使用正确的信号成功地在正确的 PID 上调用kill(),并且kill()返回0且errno=0。除了 aplay 仍在运行。
当我从命令行执行相同的序列时,除了 aplay 实际上死掉之外,一切都表现相同。
当我将 SIGQUIT 替换为 SIGKILL 时,它会按预期工作:无论effectsPlayer 如何启动,aplay 都会死亡。
我现在将把这归因于游戏中的一些奇怪现象。我不喜欢使用 SIGKILL - 可能会跳过重要的清理工作。但它有效...
答案1
您可能从引导脚本继承了对 SIGQUIT 的忽略,因为 fork 和 exec 不理会这些。在父程序中将 SIGQUIT 重置为默认状态以尝试此操作。
答案2
由于在 rc.local 下运行不太可能导致这种情况。
首先,检查父进程是否确实正在发送信号(这里可能需要一些调试行)并且子进程没有被杀死(运行 pgrep aplay,让父进程杀死,然后再次 pgrep aplay)。我还假设您没有任何 SELINUX 或其他 MAC 奇怪的情况发生。
进程不响应kill()可以归结为以下几件事:权限、处理和PID。听起来你有一个父进程“effectPlayer”,它生成一个子进程“aplay”,并且effectPlayer正在向子进程发送退出信号。
假设你没有对 setuid 和朋友做任何奇怪的事情,父母和孩子都会有相同的所有者,所以这是可以的。
退出信号可以被屏蔽,但我很确定 aplay 不会这样做。所以这是有可能的。您可以将 SIGQUIT 更改为 SIGKILL 看看它是否会改变。
最后是PID。你确定它的pid是正确的吗?再次,一些调试行指出您试图杀死的 PID,并将其与 ps 命令相匹配将对此进行测试。有时您可能会在 shell 中使用 exec 并杀死错误的进程。