QProcess的非阻塞式用法以及QApplication::processEvents的使用

一、QProcess的阻塞模式

QProcess的应用场景非常广泛。可以使用它在qt程序中执行其他进程,并与之进行通信。

当使用它执行一些终端命令和操作时,命令和操作往往是需要一定的时间的,这时QProcess本身提供了方法如:

waitForStarted() //启动阻塞,等待程序启动完毕,期间整个程序所有进程阻塞

waitForFinished() //结束阻塞,等待程序结束完毕,期间整个程序所有进程阻塞

这些方法,在主线程中使用时,都是会阻塞主线程的。

其中,以waitForFinished()为例,看函数说明就可以知道

它有一个参数,而且有默认值,它默认qprocess执行的功能最长可以运行30秒,仍未执行完,则结束它。当你把参数设置为-1时,还可以一直阻塞至程序执行完成。

二、阻塞模式的问题。

当你的程序是一个图形界面程序时,这也是qt常见的应用场景,在主线程中使用waitForFinish,则在阻塞期间,程序是无法响应界面的操作的,对外会表现为界面卡顿,而一些场景下,你希望在waitForFinish时,显示一个进度框,也是会卡的。

三、一种非阻塞式的解决方法

那么,如何实现qprocess既能有时间执行相关操作,同时,又不会阻塞呢?方法之一就是使用:

QApplication::processEvents。

它将处理所有事件队列中的事件并返回给调用者。

该函数的作用是让程序有机会去处理那些还没有处理的事件,然后再把使用权返回给调用者。

具体的解释如下:

举例:我们可以写一个非阻塞式的函数:

void ******::delayMSecs(int msec)

{

QTime Time_set = QTime::currentTime().addMSecs(msec);

while( QTime::currentTime() < Time_set )

QCoreApplication::processEvents(QEventLoop::AllEvents, 100);

}

其中processEvents参数的意义,参看上面的函数解释。

这样,可以如下使用:

m_qprocess->start(***********);

delayMSecs(1000);

会留出需要的时间,去执行start里的命令。

四,使用QApplication::processEvents时需要注意的一个问题。

这个问题就是:它可能会引起递归,导致栈溢出崩溃

举例:

bugThread.h

#include <QThread>

class BugThread : public QThread

{

Q_OBJECT

public:

BugThread(QObject* parent) : QThread(parent) {}

signals:

void sigBugsignal();

public:

void run()

{

while(true)

{

emit sigBugsignal();

}

}

};

demo.h & demo.cpp

class Demo : public QMainWindow

{

Q_OBJECT

public:

Demo(QWidget *parent = 0, Qt::WFlags flags = 0);

~Demo();

public slots:

void onBugSlot();

private:

Ui::BugsClass ui;

};

Demo::Demo(QWidget *parent, Qt::WFlags flags)

: QMainWindow(parent, flags)

{

ui.setupUi(this);

BugThread* bt = new BugThread(this);

connect(bt, SIGNAL(sigBugsignal()), this, SLOT(onBugSlot()));

bt->start();

}

void Demo::onBugSlot()

{

Sleep(1);

QApplication::processEvents();

}

如上面的代码所示:

当主线程在某个槽函数里正在执行processEvents时, 刚好有一个能响应此槽函数的信号发送过来了(肯定是其他线程发的信号), 这时就可能会发生可怕的递归,

导致栈溢出崩溃。 原因是processEvents,进入到无尽的递归中。

使用时一定注意,一定注意。

五,非阻塞方式的一些错误用法。

  1. 错误方式1:sleep

界面的线程是主线程,在主线程中使用休眠函数是一种错误,这会直接导致界面无法刷新,用户与程序无法交互,最终导致程序崩溃。linux提供的”sleep”或”usleep”函数会将你当前的线程/进程变为“睡眠”状态。 这个“睡眠”是深度意义的睡眠, 睡眠期间内核不会分配给程序时间片, 所以程序什么都不做, 更不用提界面的刷新了。

  1. 错误方式2:死循环

QTime time;

time.start();

while(time.elapsed() < 5000);

如上所示,当在死循环的时候,我们的界面是无法刷新,用户是不会响应用户的任何交互的。也就是让用户感觉程序已经是假死状态了。 从代码中我们可以发现在while循环中不停的调用elapsed()函数, 等于在这段时间内CPU完全没有机会做别的什么事情。 特别是在Linux这样非抢占式的操作系统中, 这样的死循环造成的影响是致命的, CPU被完全占用, 内核都没有机会调度进程, 别的程序拿不到时间片执行, 系统基本上就是瘫痪状态了。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QProcess可以用于启动外部进程并与其进行交互。非阻塞用法可以通过使用信号和槽机制来实现。 首先,创建一个QProcess对象,并连接所需的信号和槽函数。以下是一个示例: ```cpp // 创建QProcess对象 QProcess *process = new QProcess(this); // 连接读取输出的信号 connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput())); // 连接进程完成的信号 connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processFinished(int, QProcess::ExitStatus))); ``` 在上面的示例中,我们连接了`readyReadStandardOutput()`信号和`processOutput()`槽函数,以读取进程的输出。还连接了`finished()`信号和`processFinished()`槽函数,以在进程完成后执行一些操作。 接下来,启动进程并可以通过写入输入来与其交互。以下是一个示例: ```cpp // 启动进程 process->start("your_command"); // 写入输入 process->write("your_input"); // 等待进程完成 process->waitForFinished(); ``` 在上面的示例中,我们使用`start()`方法启动了一个外部命令。可以使用`write()`方法向进程写入输入。最后,使用`waitForFinished()`方法等待进程完成。 在`readyReadStandardOutput()`槽函数中,您可以读取进程的输出,并进行相应的处理。以下是一个示例: ```cpp void MyClass::processOutput() { QByteArray output = process->readAllStandardOutput(); // 处理输出 } ``` 在`processFinished()`槽函数中,您可以执行一些操作,例如检查进程的退出状态或输出错误信息。以下是一个示例: ```cpp void MyClass::processFinished(int exitCode, QProcess::ExitStatus exitStatus) { // 处理进程完成后的操作 } ``` 通过连接适当的信号和槽函数,您可以实现QProcess非阻塞用法,并与外部进程进行交互。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值