做项目时遭遇用户界面冻结的问题,究其原因是槽函数里装了一个需要CPU密集操作的功能。使用多线程,可以解决界面冻结的问题。
多线程的几大特点:
1.多线程的执行顺序无法保证,与操作系统的调度策略和线程优先级等因素有关。
2.多线程的切换可能发生在任何时刻、任何地点。
3.多线程对代码的敏感度高,因此对代码的细微修改都可能产生意想不到的效果。
先由一个简单的例子引出多线程
先作出这个简单的界面
“开始”对应的槽函数是:slotStart()
“停止”对应的槽函数是:slotStop()
本例中的线程(workthread类)实现的功能是,从0到9循环打印,0至9各占一排。
则该线程的具体实现如下:
#ifndef WORKTHREAD_H
#define WORKTHREAD_H
#include <QThread>
class WorkThread : public QThread
{
Q_OBJECT
public:
WorkThread();
protected:
void run();
};
#endif // WORKTHREAD_H
#include "workthread.h"
#include <QtDebug>
WorkThread::WorkThread()
{
}
void WorkThread::run()
{
while(true)
{
for(int n=0;n<10;n++)
qDebug()<<n<<n<<n<<n<<n<<n<<n<<n;
}
}
好了,现在该在本窗口对象的头文件里添加这个线程属性
private:
WorkThread *workThread[MAXSIZE];
MAXSIZE表示最大生成的线程数,可以根据个人喜好自行选择,只要你的CPU带得动。当然,这里为了展示多线程的特性,我们分别将MAXSIZE置为1及5。
完善之前两个槽函数的功能。
void CH1201::slotStart()
{
qDebug() << "slotStart";
for (int i = 0; i < MAXSIZE; i++)
{
workThread[i] = new WorkThread();
}
for (int i = 0; i < MAXSIZE; i++)
{
workThread[i]->start();
}
ui.startBtn->setEnabled(false);
ui.stopBtn->setEnabled(true);
}
void CH1201::slotStop()
{
for (int i = 0; i < MAXSIZE; i++)
{
workThread[i]->terminate();
workThread[i]->wait();
}
ui.startBtn->setEnabled(true);
ui.stopBtn->setEnabled(false);
}
线程类方法顾名思义大致都能看懂。现在多说两句我自己没怎么接触的:
1.terminate(),依次终止保存在workThread[]数组中的WorkThread类实例。但是terminate()函数并不会立刻终止这个线程,该线程何时终止取决于操作系统的调度策略。
2.wait(),使得线程阻塞等待直到退出或超时。
下面观赏一下qDebug()的结果:
下图是MAXSIZE为5是的打印结果,可以看出输出结果是乱序的,我们根本无法猜测操作系统到底是怎么调度这五个线程的。
下图是MAXSIZE为1的打印结果,输出数字顺序有规律,显然只有一个线程在工作。
PS:作为小白,IDE用的VS2015,我刚开始不知道qDebug打印的调试信息显示在哪里,查了一会儿才知道,qDebug打印的调试信息显示在console。至于调出console的方法也很简单,点击VS左上菜单之一“项目”,选择最下方的“属性”,点击“链接器”,点击“链接器”树下的“系统”,目光移到弹出窗口的中央,更改”子系统“为:”控制台/SUBSYSTEM:CONSOLE“。