C++实现POSIX兼容的shell进程暂停、恢复与终止功能问题修复
问题根因
- 非交互式shell默认忽略
SIGTSTP信号:该信号是面向终端前台场景设计的可被捕获/忽略的信号,不适合用于后台进程的暂停控制。 - 信号仅发送给shell父进程:你启动的shell命令中包含的子进程(如示例里的
sleep)和shell属于同一个进程组,仅给shell进程发信号不会影响子进程的运行状态。 - 信号选择错误:你代码中标记为“终止进程”的操作使用了
SIGSTOP,该信号的作用是暂停进程而非终止进程。
修复方案
所有修改均符合POSIX标准,可兼容macOS、Linux、BSD等系统:
- 暂停进程改用
SIGSTOP信号:POSIX规定该信号不可被捕获、不可被忽略,一定会暂停目标进程。 - 信号发送到整个进程组:给
kill传入负的PID,信号会下发到PID对应的整个进程组,覆盖shell及其所有子进程。 - 终止进程改用
SIGTERM或SIGKILL信号:SIGTERM为优雅终止信号,允许进程做清理操作;SIGKILL为强制终止信号,不可被阻塞。 - 移除无用的管道逻辑:你原代码中创建了标准输入输出管道但未使用,移除后可避免文件描述符泄漏。
修改后代码
简化后的system2函数
#include <unistd.h> #include <fcntl.h> #include <sys/wait.h> int system2(const char * command) { int pid = fork(); if (pid < 0) { return pid; } else if (pid == 0) { // 把标准输入输出错误重定向到/dev/null,按需可保留 dup2(open("/dev/null", O_RDONLY), 0); dup2(open("/dev/null", O_WRONLY), 1); dup2(open("/dev/null", O_WRONLY), 2); /// 关闭所有其他描述符 for (int i = 3; i < 4096; ++i) close(i); setsid(); execl("/bin/sh", "sh", "-c", command, NULL); _exit(1); } return pid; }
修改后的主函数
#include <iostream> #include <thread> #include <chrono> #include <signal.h> int main() { const char * command = "for i in {1..1000}; do echo $i >> /Users/remi/test/data.txt; sleep 1s;done"; auto pid = system2(command); std::cout << "pid = " << pid << std::endl; std::cout << "process should be running!" << std::endl; std::this_thread::sleep_for(std::chrono::seconds(10)); // 暂停整个进程组 kill(-pid, SIGSTOP); std::cout << "process should be paused!" << std::endl; std::this_thread::sleep_for(std::chrono::seconds(10)); // 恢复整个进程组 kill(-pid, SIGCONT); std::cout << "process should be running!" << std::endl; std::this_thread::sleep_for(std::chrono::seconds(10)); // 终止整个进程组 kill(-pid, SIGTERM); // 等待进程退出,避免僵尸进程 waitpid(pid, NULL, 0); std::cout << "process should be stopped!" << std::endl; std::this_thread::sleep_for(std::chrono::seconds(10)); return 0; }
注意事项
如果不需要后台进程脱离当前会话,可以删除system2函数中的setsid()调用,此时仍可通过进程组的方式发送信号,效果一致。
内容的提问来源于stack exchange,提问作者Remi.b
相关产品推荐
相关产品推荐

