Windows下cmd.exe关闭时进程终止的原因及解决方案问询
问题解析与解决方案
为什么会出现这种差异?
这本质是Windows系统中控制台会话关联和进程管理机制导致的:
- 当你在
cmd.exe里启动prog1.exe时,prog1会继承cmd的控制台会话。而prog1通过boost::process::spawn启动prog2时,默认情况下prog2也会继承这个控制台会话,属于同一个控制台进程组。 prog1.exe退出时,它只是prog2的父进程,但Windows默认不会因为父进程终止而强制终止子进程(除非父进程通过作业对象绑定了子进程),所以prog2能继续运行。- 当你关闭
cmd.exe时,Windows会向所有关联到该控制台会话的进程发送CTRL_CLOSE_EVENT关闭信号,绝大多数进程会响应这个信号终止运行,这就是prog2被提前终止的原因。
如何避免关闭cmd.exe时终止prog2.exe?
这里有几种可靠的解决方法,按推荐度排序:
1. 让prog2脱离控制台会话(推荐)
使用Boost.Process提供的Windows平台专属参数boost::process::windows::detach,让prog2启动时脱离原控制台,这样它就不再和cmd的控制台会话关联,关闭cmd也不会影响它:
#include <boost/process.hpp> #include <boost/process/windows.hpp> namespace bp = boost::process; int main() { // 启动prog2并脱离控制台 bp::spawn("prog2.exe", bp::windows::detach); return 0; }
2. 不继承父进程的控制台
如果你需要更精细的控制,可以通过设置CreateProcess的DETACHED_PROCESS标志(Boost.Process可以映射这个标志),让prog2不继承prog1的控制台:
bp::spawn("prog2.exe", bp::windows::create_process_args(DETACHED_PROCESS));
3. 将prog2放入独立的作业对象
你可以手动创建一个Windows作业对象,将prog2加入其中,配置作业对象不随父控制台关闭而终止进程。不过这种方法相对复杂,适合需要更高级进程管理的场景:
#include <windows.h> #include <boost/process.hpp> namespace bp = boost::process; int main() { // 创建作业对象 HANDLE hJob = CreateJobObject(nullptr, nullptr); if (hJob == nullptr) { // 处理错误 return 1; } // 配置作业对象:关闭作业时不终止进程 JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {0}; jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; jeli.BasicLimitInformation.LimitFlags &= ~JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)); // 启动prog2并加入作业 bp::child c("prog2.exe"); AssignProcessToJobObject(hJob, c.native_handle()); // 关闭作业句柄(不影响进程) CloseHandle(hJob); return 0; }
额外说明
如果你的场景允许prog2弹出新的控制台窗口,也可以用CREATE_NEW_CONSOLE标志启动它,这样它会拥有独立的控制台,关闭原cmd也不会影响它,但这种方法会额外打开一个窗口,可能不符合需求。
内容的提问来源于stack exchange,提问作者Andrew Tomazos




