阅读量:0
前言
本文在上一篇【QT常用技术讲解】tableWidget右键菜单及多进程编程的基础上,加入多线程,解决调用进程执行后台命令导致QT程序卡顿的现象。
概述
QT应用本身是一个进程,当通过QProcess创建一个进程来执行其他任务时,QT应用是被阻塞的,必须等待QProcess创建的进程执行完,才能继续往下执行,这是典型的进程阻塞模式。而使用多线程,则是“并行执行”的效果,此时QT应用就不会有卡顿现象,多线程是QT项目处理卡顿现象最常用的方法。
功能讲解
增加通用的执行后台命令的线程类,下面为threadCmd.h的源码:
#ifndef THREADCMD_H #define THREADCMD_H #include <QThread> #include <QJsonDocument> #include <QJsonObject> #include <QJsonArray> #include <QString> #include "src/util/comm_define.h" class ThreadCmd : public QThread { Q_OBJECT public: explicit ThreadCmd(const QString ¶m,QObject *parent = nullptr) ; protected: void run() override; signals: void callback(const QString result); private: QString m_param; }; #endif // THREADCMD_H
以下为threadCmd.cpp的源码:
#ifndef THREADCMD_CPP #define THREADCMD_CPP #include "threadCmd.h" #include <QDebug> #include <QProcess> #include "src/util/comm_define.h" #include <QTextCodec> ThreadCmd::ThreadCmd(const QString ¶m,QObject *parent) : QThread(parent),m_param(param) { } void ThreadCmd::run(){ QProcess process; // 执行命令 QString cmd = m_param; qDebug() << __LINE__ << cmd; process.start(cmd); if(process.waitForFinished()){ // 读取进程的输出 QString output = QString::fromLocal8Bit(process.readAllStandardOutput()); QTextCodec *codec = QTextCodec::codecForName("GBK"); QString unicodeOutput = codec->toUnicode(output.toLocal8Bit()); emit callback(unicodeOutput); }else{ emit callback("[error]:命令执行失败"); } // 进程使用完毕后,可以手动删除 process.deleteLater(); } #endif // THREADCMD_CPP
ping对话框涉及的改动点,pingdialog.h调整代码如下
private slots: void ThreadsendResult(const QString &result);//执行后台命令的槽函数 void ThreadkillProc(const QString &result);//执行kill进程的槽函数
pingdialog.cpp调整代码如下
void pingDialog::on_start_clicked() { ui->textBrowser->setReadOnly(false);// ui->textBrowser->setText("--------ping start--------"); QString times = ui->timeBox->currentText(); QString Ipstr=ui->ipEdit->text(); QString cmd = QString("ping -n %1 %2").arg(times).arg(Ipstr); m_isStart=true; //把调用QProcess执行后台命令的代码改成调用多线程类 ThreadCmd *thread = new ThreadCmd(cmd, this); //等待多线程的callback信号,关联ThreadsendResult槽函数来处理结果 connect(thread, &ThreadCmd::callback, this, &pingDialog::ThreadsendResult); thread->start(); } void pingDialog::on_stop_clicked() { if(m_isStart==true){ ui->textBrowser->setReadOnly(false);// ui->textBrowser->setText("--------ping stop--------"); //QString cmd = QString("pkill ping");//linux执行的 QString cmd = QString("taskkill /IM ping.exe /F"); ThreadCmd *thread = new ThreadCmd(cmd, this); connect(thread, &ThreadCmd::callback, this, &pingDialog::ThreadkillProc); thread->start(); } } void pingDialog::ThreadsendResult(const QString &result) { qDebug() << "ThreadsendResult finished with result:" << result; ui->textBrowser->append(result); ThreadCmd *thread = qobject_cast<ThreadCmd *>(sender()); if (thread) { thread->deleteLater(); // 删除线程对象 } m_isStart=false; } void pingDialog::ThreadkillProc(const QString &result) { qDebug() << "ThreadkillProc finished with result:" << result; ThreadCmd *thread = qobject_cast<ThreadCmd *>(sender()); if (thread) { thread->deleteLater(); // 删除线程对象 } }
注意事项
并非所有的事务都要开线程来处理,QT本身已经有很好的机制来处理前端互动的效果了。开了线程一定有损耗(创建、回收等),必定会影响性能,做为C/C++开发者,写代码必须得考虑性能的因素。
而阻塞模式对性能的影响很大,远远超出线程的消耗,常见的阻塞方式有:
1、通过进程打开“第三方”应用;
2、网络编程的等待及响应;