Qt+Win32进行简单的多进程管理

项目需要将算法放到独立的进程运行,一来避免了算法不稳定导致主程序崩溃,二来避免了多个算法库的依赖冲突。主程序和子程序之间可用 Socket、共享内存、管道等方式进程交互,复杂的也可以上 RPC 框架。

本来首先想到的是使用 QProcess 来启动子进程,但是启动之后想要结束或者是判断进程状态属实不方便,索性直接全用 Win32 的接口来操作。由于需求简单,只是一个主程序对应多个子进程的形式,所以也不需要设计什么进程调度,只需要启动、关闭和检测进程运行状态。分别查找对应的接口:

首先是启动进程,百度到主要有四种接口,参照:https://blog.csdn.net/qq_43812868/article/details/108188987,为了方便创建进程时拿到对应的句柄,没用 CreateProcess,选择了 ShellExecuteEx,大致如下:

    //初始化
    SHELLEXECUTEINFOW se_info = { 0 };
    //memset(&se_info, 0x00, sizeof(SHELLEXECUTEINFOW));
    //in.required.此结构体字节大小
    se_info.cbSize = sizeof(SHELLEXECUTEINFOW);
    //in.SEE_MASK_NOCLOSEPROCESS用于指示hProcess成员接收到进程句柄。
    se_info.fMask = SEE_MASK_NOCLOSEPROCESS;
    //in.optional.父窗口的句柄,用于显示系统在执行此功能时可能产生的任何消息框。该值可以为NULL。
    //se_info.hwnd = NULL;
    //in.optional.要执行的动作,open打开指定lpFile文件,runas管理员身份启动应用程序
    se_info.lpVerb = L"open";
    //in.以空值结尾的字符串的地址
    se_info.lpFile = reinterpret_cast<LPCWSTR>(info_path.utf16());
    //in.optional.执行参数
    se_info.lpParameters = reinterpret_cast<LPCWSTR>(info_arg.utf16());
    //in.optional.工作目录,为NULL则使用当前目录
    //se_info.lpDirectory = NULL;
    //in.required.SW_HIDE隐藏该窗口并激活另一个窗口,打开的进程不会显示窗口
    //因为hide不显示窗口,测试/调试时可以用SW_SHOW
    se_info.nShow = info.visible ? SW_SHOW : SW_HIDE;
    //out.如果设置了SEE_MASK_NOCLOSEPROCESS并且ShellExecuteEx调用成功,它将把该成员设置为大于32的值。
    //如果函数失败,则将其设置为SE_ERR_XXX错误值,以指示失败的原因。
    //se_info.DUMMYUNIONNAME;
    //out.valid when SEE_MASK_NOCLOSEPROCESS 新启动的应用程序的句柄,如果未启动则为NULL
    //se_info.hProcess;

    qDebug()<<"execute exe."<<info.path<<info.key<<info.args;
    //ShellExecuteEx创建的进程可以提权
    //CreateProcess继承权限,但可以更好地控制
    if(::ShellExecuteExW(&se_info)){
        if(se_info.hProcess != NULL){
            auto hProcess = se_info.hProcess; //拿到句柄
            qDebug()<<"execute success.";
        }
    }
    qDebug()<<"execute fail."<<(intptr_t)(HINSTANCE)se_info.hInstApp;

启动之后就将启动参数和句柄放到列表中,主进程轮询检测子进程是否运行正常,如果异常则重新启动该进程。子进程也可以轮询检测主进程执行状态,异常则自动退出进程,我是通过启动参数的方式将主进程 pid 传递给的子进程,然后以 OpenProcess 接口来拿到对应的句柄。检测进程是否运行我是用 GetExitCodeProcess,大致如下:

    //检查所有进程的状态,并重置计数
    for(auto iter = processTable.begin(); iter != processTable.end(); iter++)
    {
        const ProcessInfo &node = iter.value();
        DWORD exit_code;
        //检测进程是否正常运行,把需要重启的重启(hProcess为进程句柄)
        ::GetExitCodeProcess(node.hProcess,&exit_code);
        //如果进程尚未终止且函数成功,则返回的状态为STILL_ACTIVE
        if(exit_code!=STILL_ACTIVE){
              //如果异常可以选择自动重启进程
        }
    }

最后,主程序也可以主动关闭进程,使用 TerminateProcess 来完成,大致如下:

        //从列表取对应的进程句柄进程关闭
        if(::TerminateProcess(hProcess,-1)){
            qDebug()<<"terminate success.";
        }

(2021-9-22)补充:每个启动参数最好用双引号括起来,避免解析时遇到空格被拆开了。

我做的一个小 Demo:

github 链接:https://github.com/gongjianbo/MyTestCode/tree/master/Qt/MultiProcess_Win​​​​​​​

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龚建波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值