QProcess简介
QProcess可以用于启动外部程序,它提供了一系列函数来启动、控制和与外部进程进行交互。
作用:
1. 启动外部进程: 通过start函数
2. 进程状态和控制:判断进程是否正在运行、等待进程完成、终止进程等。如stateChanged信号
3. 进程通信: 支持与外部进程进行通信。可以通过管道(标准输入、标准输出和标准错误输出)进行输入和输出操作。readyReadStandardOutput信号
4. 信号和槽机制:QProcess使用信号和槽机制来处理与外部进程相关的事件。例如,当外部进程完成时,可以使用finished信号来通知应用程序。
进程id:
qint64 processId() const;
启动进程
一体式
以子进程的方式启动外部程序,外部进程与主程序互不干扰,但外部进程的父进程就是主程序。代码非阻塞。
当主程序退出时,被主程序调用起来的进程也退出。
void start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode = ReadWrite)
void start(QIODevice::OpenMode mode = ReadWrite)
program:启动外部应用程序的路径。不包含空格,包含空格需要在arguments中传入
arguments:传入待启动外部程序的参数,即:int main(int argc, char *argv[])这里的参数。
如果在启动前已经用 setProgram() 和 setArguments() 指定了程序和参数,那么直接调用第二种 start() 函数即可启动;如果没有指定,那么调用第一种 start() 时需要将程序和参数传入参数列表中。
延伸:判断是否启动成功有2种办法
办法1.调⽤start()函数或open()函数启动进程。在程序启动后,QProcess进⼊运⾏状态并发出started()信号
//启动完毕
connect(process, &QProcess::started, this, [=]()
{
qDebug() << "started:" ;
});
办法2.使用waitForStarted()函数——阻塞直到进程开始
分离式
以分离的方式启动外部程序,外部程序与主程序互不干扰,外部进程的父进程是系统的 init 进程。
外部程序启动程序后,主程序退出时,被调用的进程继续执行,不退出。代码非阻塞。
static bool startDetached(const QString &program, const QStringList &arguments,
const QString &workingDirectory = QString() , qint64 *pid = nullptr);
execute
QProcess类的静态函数,以阻塞的方式启动外部程序,只有外部程序执行完成后,主程序才会继续执行。外部程序的标准输出、标准错误都是重定向到主程序的标准输出和标准错误的。
退出进程
void kill()
void terminate()
close()
kill()
作用是杀死当前进程使之退出。这个函数也是调用平台相关的 API,
在 Windows 上调用 TerminateProcess,
而在 Unix 和 macOS 上是将 SIGKILL 信号发送到进程中。
terminate()
区别于 kill() 这种暴力的退出不同,它在退出进程的时候是有机会提示用户输入任何为保存的文件等。
在 Windows 上是发送 WM_CLOSE 到进程的顶级窗口,然后发到进程本身的主线程。
而 在 Unix 和 macOS 上是发送 SIGTERM 信号。
注意在 Windows 上,没有事件循环或者不处理 WM_CLOSE 消息的控制台程序只能调用 kill() 来终止。
close()
其中 QProcess::close() 调用 QProcess::kill()
延伸:判断进程退出情况
当进程退出时,QProcess重新进⼊NotRunning状态(初始状态),并发出finish()信号。
connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(onFinishProcess(int,QProcess::ExitStatus)));
void onFinishProcess(int exitCode, QProcess::ExitStatus exitStatus);
void Dialog::onFinishProcess(int exitCode, QProcess::ExitStatus exitStatus)
{
if(exitStatus == QProcess::NormalExit)
{
qDebug() << "程序正常结束";
}
else
{
qDebug() << "程序异常结束";
}
}
process类有close和kill方法
两者的区别是kill是立即终止进程实体,相当于在进程管理器窗口中执行结束进程操作;但process组件/对象的进行信息还在,包括进程关闭时间等信息可以查看。
close方法是释放组件/对象资源。这时进程不一定终止,但当前操作的组件/对象资源却被释放,后续无法再使用process实例访问。
延伸:关闭第三方进程
windows平台上
QProcess process;
process.execute("taskkill /im xx.exe /f");
Linux平台上
如在Ubuntu中可以使用kill或者pkill命令来终止进程。
QString scriptPath = "test";
arguments << scriptPath;
QProcess process;
process.start("pkill", arguments);
终止进程的两个命令pkill和kill
kill命令
通过向指定进程发送信号来终止进程。
信号可以是SIGTERM、SIGKILL等。
kill命令需要提供进程ID才能终止进程。
pkill命令
pkill命令通过匹配名称或其他属性来终止进程。
pkill命令使用-f和-P标志指定要匹配的进程属性。
pkill命令不需要知道进程ID,但需要提供进程名称或其他属性。
主要区别
进程标识:kill需要,pkill不需要。
名称匹配:kill不支持,pkill支持。
其他属性匹配:kill不支持,pkill支持。
强制终止:kill支持,pkill不支持。
使用场景
终止特定进程:可以使用kill命令通过指定PID终止特定进程。
终止具有相同名称的进程组:可以使用pkill命令通过名称终止具有相同名称的进程组。
终止具有特定属性的进程:可以使用pkill命令通过匹配进程的其他属性终止进程。
强制终止进程:可以使用kill命令声音SIGKILL信号强制终止进程
同步进程
waitForStarted()函数——阻塞直到进程开始。
waitForReadyRead()函数——阻塞直到有新数据可在当前读取通道上读取为⽌。
waitForBytesWritten()函数——阻塞直到将⼀个有效载荷数据写⼊该进程为⽌。
waitForFinished()函数——阻塞直到过程完成。
通道通信
进程具有两个预定义的输出通道:
标准输出通道(stdout)提供常规控制台输出。
标准错误通道(stderr)通常提供由进程打印的错误。
进程的输出通道与QProcess的读取通道相对应,⽽进程的输⼊通道与QProcess的写⼊通道相对应。这是因为我们使⽤QProcess读取的内容是进程的输出,⽽我们编写的内容则成为进程的输⼊。
当有新的标准输出数据可⽤时,它也会发出readyReadStandardOutput()信号,⽽当有新的标准错误数据可⽤时,它会发出readyReadStandardError()信号。
connect(process, &QProcess::readyReadStandardOutput, this, [=]()
{
QString qstr(process->readAllStandardOutput());
qDebug() << "readyReadStandardOutput:" << qstr;
});
QByteArray readAllStandardOutput(); //标准输出通道信息
QByteArray readAllStandardError(); //标准错误通道信息
延伸:如在windows系统上使用QProcess类来判断特定进程是否正在运行
bool isProcessRunning(const QString& processName)
{
QProcess process;
process.start("tasklist", QStringList() << "/FI" << "IMAGENAME eq " + processName);
process.waitForFinished();
QString output = process.readAllStandardOutput();
QStringList processes = output.split("\n");
processes.removeFirst(); // 移除第一行标题
foreach(QString line, processes) {
if (line.contains(processName))
return true;
}
return false;
}
延伸:获取环境变量
#include <QCoreApplication>
#include <QProcessEnvironment>
#include <QString>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
// 获取环境变量"PATH"的值
QString path = env.value("PATH");
qDebug() << "PATH:" << path;
return a.exec();
}
进程的状态
enum ProcessState {
NotRunning,
Starting,
Running
};
获取进程的状态:
QProcess::ProcessState state() const;
进程状态改变的信号
进程状态改变,会发出该信号
void stateChanged(QProcess::ProcessState state, QPrivateSignal);
connect(process, &QProcess::stateChanged, this, [=](QProcess::ProcessState state)
{
qDebug() << "show state:";
switch (state)
{
case QProcess::NotRunning:
qDebug() << "Not Running";
break;
case QProcess::Starting:
qDebug() << "Starting";
break;
case QProcess::Running:
qDebug() << "Running";
break;
default:
qDebug() << "otherState";
break;
}
});
Linux环境
1. 查看进程命令
使用ps命令:
ps命令可以显示当前系统中正在运行的进程。常用的选项有:
ps aux:显示所有用户的所有进程。
ps -ef:显示所有进程的完整信息。
延伸:`ps -ef`和`ps -eo`都是Linux系统中用于查看进程的命令,但它们的主要区别在于输出的格式和内容。
`ps -ef`命令用于显示系统中所有进程的列表,包括其他用户的进程。输出的内容包括UID(用户ID)、PID(进程ID)、PPID(父进程ID)、C(CPU占用率)、STIME(启动时间)、TTY(终端类型)、TIME(CPU时间)以及CMD(命令行)。这种格式提供了关于进程的详细信息,有助于系统管理员和开发人员了解系统中正在运行的进程情况。
而`ps -eo`命令允许用户自定义输出的格式,通过指定不同的参数来选择要显示的列。例如,`ps -eo comm`命令将只显示进程的命令行部分,而不包括其他信息。这使得用户能够根据需要灵活选择需要查看的进程属性,从而更精确地了解进程的状态和行为。
因此,`ps -ef`和`ps -eo`的主要区别在于输出的格式和内容。前者提供了全面的进程列表,后者则允许用户自定义输出的列以满足特定需求。
启动程序
程序名:test 启动脚本:test.sh 结束脚本stop_test.sh
Linux环境
脚本启动
如test.sh 启动脚本
#!/bin/sh
current_Dir=$(pwd);
export LD_LIBRARY_PATH=$current_Dir/allso
$current_Dir/PERT_FS
更高级一点。但测试发现,没有启动进程,也被报出已启动,不知道为啥
#!/bin/sh
current_Dir=$(pwd);
if pgrep -f "test" > /dev/null; then
echo "test已启动。"
else
Export LD_LIBRARY_PATH=$current_Dir/allso
$current_Dir/test & echo "test启动成功。
fi
QT代码启动
Qt代码启动sh脚本,再让sh脚本启动程序
QString scriptPath = "/home/glh/study/demo/Debug/test.sh";
if(m_process == nullptr)
{
m_process = new QProcess();
}
connect(m_process, &QProcess::started , this , &Dialog::onStartProcess);
m_process->start(scriptPath);
void Dialog::onStartProcess()
{
QString outputText = "success to start script";
ui->textEdit_Result->setText(outputText);
}
Qt代码直接启动程序
QString scriptPath = "/home/glh/study/demo/Debug/test";
if(m_process == nullptr)
{
m_process = new QProcess();
}
connect(m_process, &QProcess::started , this , &Dialog::onStartProcess);
m_process->start(scriptPath);
void Dialog::onStartProcess()
{
QString outputText = "success to start script";
ui->textEdit_Result->setText(outputText);
}
windows环境
QT代码直接启动
void Dialog::on_pushButton_clicked()
{
QString scriptPath = "C:/study/test.exe";
if(m_process == nullptr)
{
m_process = new QProcess();
}
connect(m_process, &QProcess::started , this , &Dialog::onStartProcess);
m_process->start(scriptPath);
}
void Dialog::onStartProcess()
{
QString outputText = "success to start script";
ui->textEdit->setText(outputText);
}
结束程序
进程名:test 启动脚本名:test.sh 结束进程脚本名:stop_test.sh
Linux环境
脚本结束
如stop_test.sh 脚本
#!/bin/bash
# 使用pgrep查找进程名称
PID=$(pgrep test)
# 检查是否找到了进程
if [ ! -z "$PID" ]; then
# 如果找到了进程,结束该进程
kill $PID
fi
QT代码结束
Qt代码直接结束自己启动的程序
重点是调m_process->close();
void Dialog::on_pushButton_StartGrpc_clicked()
{
QString scriptPath = "/home/glh/study/demo/Debug/test";
if(m_process == nullptr)
{
m_process = new QProcess();
}
connect(m_process, &QProcess::started , this , &Dialog::onStartProcess);
connect(m_process, &QProcess::readyReadStandardOutput , this , &Dialog::onReadStandardOutput);
connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(onFinishProcess(int,QProcess::ExitStatus)));
m_process->start(scriptPath);
}
void Dialog::onFinishProcess(int exitCode, QProcess::ExitStatus exitStatus)
{
if(exitStatus == QProcess::NormalExit)
{
qDebug() << "程序正常结束";
}
else
{
qDebug() << "程序异常结束";
}
}
void Dialog::on_pushButton_StopGrpc_clicked()
{
if(m_process == nullptr)
return;
m_process->close();
}
QT代码直接结束不是自己程序启动的别的进程
使用pkill命令
QStringList arguments;
QString scriptPath = "test";
arguments << scriptPath;
QProcess process;
process.start("pkill", arguments);
QString outputText;
// 等待命令执行完毕,或者设置一个超时时间
if (!process.waitForFinished())
{
outputText = "Failed to end the script";
}
else
{
outputText = "success to end the script";
}
ui->textEdit_Result->clear();
ui->textEdit_Result->setText(outputText);
使用kill命令
QProcess process;
QStringList arguments;
QString scriptPath = "PERT_FS";
arguments << scriptPath;
process.start("pgrep",arguments);
process.waitForFinished(); // 等待命令执行完毕
QStringList pidList = QString(process.readAllStandardOutput()).trimmed().split("\n");
for (const QString &pid : pidList)
{
process.start("kill", QStringList() << pid);
}
QString outputText;
// 等待命令执行完毕,或者设置一个超时时间
if (!process.waitForFinished())
{
outputText = "Failed to end the script";
}
else
{
outputText = "success to end the script";
}
ui->textEdit_Result->clear();
ui->textEdit_Result->setText(outputText);
windows环境
QT代码直接结束自己启动的进程
重点是调m_process->close();
void Dialog::on_pushButton_clicked()
{
QString scriptPath = "C:/study/test.exe";
if(m_process == nullptr)
{
m_process = new QProcess();
}
connect(m_process, &QProcess::started , this , &Dialog::onStartProcess);
connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(onFinishProcess(int,QProcess::ExitStatus)));
m_process->start(scriptPath);
}
void Dialog::onFinishProcess(int exitCode, QProcess::ExitStatus exitStatus)
{
if(exitStatus == QProcess::NormalExit)
{
qDebug() << "程序正常结束";
}
else
{
qDebug() << "程序异常结束";
}
QString outputText = "success to stop script";
ui->textEdit->setText(outputText);
}
void Dialog::on_pushButton_2_clicked()
{
if (m_process)
{
m_process->close();
}
}
经测试过,如果是在任务管理器中手动删除进程test.exe.则程序正常结束。如果是调on_pushButton_2_clicked,通过调用 m_process->close()函数,则为程序异常结束。
QT代码直接结束不是自己程序启动的别的进程
如手动启动 test.exe程序,通过代码关闭它
void Dialog::on_pushButton_3_clicked()
{
QProcess process;
process.execute("taskkill /im test.exe /f");
}
判断进程是否在运行
Windows环境
QString strProcessName = “test”;
bool bResult = false;
// 判断进程是否存在
QProcess tasklist;
tasklist.start("tasklist",
QStringList() << "/NH"
<< "/FO" << "CSV"
<< "/FI" << QString("IMAGENAME eq %1").arg(strProcessName));
tasklist.waitForFinished();
QString strOutput = tasklist.readAllStandardOutput();
//如果进程存在,则结束进程
if (strOutput.contains(QString("\"%1").arg(strProcessName),Qt::CaseInsensitive))
{
bResult = true;
}
return bResult;
Linux环境
QString strProcessName = “test”;
QString strExePath = "/home/gl/study/demo/test";
bool bResult = false;
QString command = "ps -eo pid,cmd | grep \" " + strExePath + "\" " + "| grep -v grep";
// 创建并执行子进程
QProcess process;
process.start("bash", QStringList() << "-c" << command);
process.waitForFinished();
// 获取输出结果
QByteArray outputBytes = process.readAllStandardOutput();
QString strOutput = QString::fromUtf8(outputBytes);
QStringList applist = strOutput.split("\n");
for (int i = 0; i < applist.size();i++)
{
bool bContains = strOutput.contains(QString("%1").arg(strProcessName),Qt::CaseInsensitive);
if (bContains)
{
bResult = true;
break;
}
}
return bResult;
QProcess start是否结束
转载本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。
上一篇:怎样把蓝牙地址写到NFC上
下一篇:对一列数据进行连续统计MySQL
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
Android开发32g笔记本电脑够吗
原标题:华为二合一笔记本支持Android可能是鸡肋!华为手机销量猛增无疑让华为高兴,不过面对华为提出提出其消费者BG要在5年内实现千万收入,压力颇大,单靠手机业务显然难以实现,在小米推出笔记本的示范效应下,华为推出笔记本是很正常的情况,在过去几年,华为一直都在学习小米的营销模式。让人诧异的是华为的二合一笔记本产品是一个双系统产品,即是加上键盘是使用Windows系统的笔记本,拆掉键盘就是Andr
Android开发32g笔记本电脑够吗 华为笔记本开发android Android Windows 手机市场