一、QProcess的阻塞模式

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

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

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

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

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

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




windows recvfrom设置非阻塞 createprocess非阻塞_非阻塞


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

二、阻塞模式的问题。

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

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

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

QApplication::processEvents。

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

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

具体的解释如下:


windows recvfrom设置非阻塞 createprocess非阻塞_主线程_02


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

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); 
processEvents();
}

如上面的代码所示:

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

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

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

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

  1. 错误方式1:sleep

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

  1. 错误方式2:死循环

QTime time;

time.start();

while(time.elapsed() < 5000);

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