Qt系列文章——QProcess使用

第一章 QProcess使用



文章目录

  • Qt系列文章——QProcess使用
  • QProcess可以用来做什么
  • 一、使用QProcess执行linux系统命令
  • 1.具体代码
  • 2.注意事项
  • 二、QProcess启动外部进程
  • 1、代码
  • 2、使用QProcess结束外部进程的问题
  • linux系统下处理QProcess发出的SIGTERM信号
  • process_exit_by_signal.h文件定义
  • process_exit_by_signal.cpp实现
  • main.c调用



QProcess可以用来做什么

  1. 在微服务架构下可以用来启动外部进程;
  2. QProcess可以用来执行windows/linux等系统命令。

一、使用QProcess执行linux系统命令

下面给出示例代码来介绍QProcess执行系统命令

1.具体代码

代码如下:

QString MainWindow::qprocess_exe_cmd( CMD_TYPE type , QString cmd , QStringList arg )
{
    QProcess process;
    QString cmd_temp;
    //普通权限执行命令
    if( type == user )
    {
        cmd_temp = cmd;
    }
    //超级管理员权限
    if( type == super )
    {
        cmd_temp = "sh -c" ;
        cmd_temp += " \"echo ";
        cmd_temp += "xxxxxx";   //密码
        cmd_temp += " | sudo -S ";
        cmd_temp += cmd;
        cmd_temp += "\"";
    }
    qDebug() << cmd_temp;
    process.start(cmd_temp);
    process.waitForFinished();
    QString output = process.readAllStandardOutput();

    QProcess::ProcessError err = process.error();


    //qDebug() << output;
    return output;
}

2.注意事项

  • 启动超级用户密码需要修改为自己的;
  • QProcess执行命令尽量不要在主UI线程内部,否则会导致主UI线程卡顿;

二、QProcess启动外部进程

1、代码

#include "process_mangament.h"

/*
 * 功能规划:
 *  1、应具备多进程管理能力;[完成]
 *  2、子进程启动有点慢;
 */

///
/// \brief profiler_show_com::profiler_show_com
/// \param exe_path_name:exe软件的路径路径,这个路径一定是相对于主进程的相对路径
/// \param argument:软件运行参数
/// \param parent:
///
process_mangament::process_mangament(QString exe_path_name,QStringList argument)
{
    QProcess::ProcessError te;
    exe_path_name.remove("./");
    this->exe_path_name = qApp->applicationDirPath() + "/" + exe_path_name;
    this->p_process.append(new QProcess);
    //---------------------------------------------------------------------
    //启动进程
    if( QFileInfo::exists(this->exe_path_name) )
    {
        this->p_process.at(0)->start(this->exe_path_name,argument);
        te = this->p_process.at(0)->error();
        this->p_process.at(0)->waitForStarted(6000);
    }
    else
    {
        qDebug("路径错误,并不存在\r\n");
    }
}

///
/// \brief profiler_show_com::~profiler_show_com
///
process_mangament::~process_mangament(void)
{
    //结束进程
    for( int i = 0 ; i < p_process.size() ; i++ )
    {
        this->p_process.at(i)->terminate();
        //等待结束,否则会报错
        this->p_process.at(i)->waitForFinished(3000);
        delete p_process.at(i);
    }
}


///
/// \brief process_mangament::add_new_process 增加新的进程到进程管理器
/// \param exe_path_name:相对于主进程.exe所在的相对路径
/// \param argument:参数
///
void process_mangament::add_new_process(QString exe_path_name,QStringList argument)
{
    QProcess::ProcessError te;
    //新的进程加入到list中进行管理
    this->p_process.append(new QProcess);
    exe_path_name.remove("./");
    this->exe_path_name = qApp->applicationDirPath() + "/" + exe_path_name;
    //---------------------------------------------------------------------
    //启动进程
    int index_last = p_process.size() - 1;
    if( QFileInfo::exists(this->exe_path_name) )
    {
        this->p_process.at(index_last)->start(this->exe_path_name,argument);
        te = this->p_process.at(index_last)->error();
        this->p_process.at(index_last)->waitForStarted(6000);
    }
    else
    {
        qDebug("路径错误,并不存在\r\n");
    }
}

2、使用QProcess结束外部进程的问题

  1. Qt官方给出的QProcess在win和linux上的不一致,也就是说如果Unix系统用QProcess启动的进程,那么进程内部要自己处理SIGTERM信号来正确的解决进程,否则进程内部使用的资源是无法正确结束的;
Attempts to terminate the process.
The process may not exit as a result of calling this function (it is given the chance to prompt the user for any unsaved files, etc).
On Windows, terminate() posts a WM_CLOSE message to all top-level windows of the process and then to the main thread of the process itself. On Unix and macOS the SIGTERM signal is sent.
Console applications on Windows that do not run an event loop, or whose event loop does not handle the WM_CLOSE message, can only be terminated by calling kill().
See also kill().

linux系统下处理QProcess发出的SIGTERM信号

process_exit_by_signal.h文件定义
#ifndef PROCESS_EXIT_BY_SIGNAL_H
#define PROCESS_EXIT_BY_SIGNAL_H

#include <QCoreApplication>
#include <signal.h>
#include <unistd.h>

//通过signal结束进程

#if defined(__linux__) || defined(__linux)


void catch_sigterm(QCoreApplication &app);
#endif

#endif // PROCESS_EXIT_BY_SIGNAL_H
process_exit_by_signal.cpp实现
#include <./process_manage/process_exit_by_signal.h>


/*
 * 1、有了这个功能,才能通过QProcess的terminat正常结束进程,否则进程是没有正确结束的;
 * 2、这个功能可以同时结束在qt中直接点击运行结束退出不正常的问题;
 */
///
/// \brief sig_term_handler
/// \param signum
/// \param info
/// \param ptr
/// 如果捕捉到进程结束信号那么关闭
static QCoreApplication * p_a;
void sig_term_handler(int signum, siginfo_t *info, void *ptr)
{
    Q_UNUSED(signum);
    Q_UNUSED(info);
    Q_UNUSED(ptr);
    //通知所有程序退出
    p_a->quit();
}

///
/// \brief catch_sigterm:设置捕捉系统退出信号
///
void catch_sigterm( QCoreApplication &app )
{
  static struct sigaction _sigact;

  memset(&_sigact, 0, sizeof(_sigact));
  _sigact.sa_sigaction = sig_term_handler;
  _sigact.sa_flags = SA_SIGINFO;
  //设置信号捕捉
  sigaction(SIGTERM, &_sigact, NULL);
  //获取app地址,结束时要用
  p_a = &app;
}
main.c调用
#include "myqcoreapplication.h"
#include "process_manage/process_exit_by_signal.h"


//子线程需要连接QCoreApplication的quite信号
//通过QLibray导入传感器的动态连接库
int main(int argc, char *argv[])
{
    myQCoreApplication a(argc, argv);
    //捕捉异常信号控制进程,正常退出
    catch_sigterm(a);
    return a.exec();
}