天天看点

QT学习:多线程

一、优势。

(1)提高应用程序的响应速度。这对于开发图形界面的程序尤为重要,当一个操作耗时很长时,整 个系统都会等待这个操作,程序就不能响应键盘、鼠标、菜单等的操作,而使用多线程技术可将耗时长的 操作置于一个新的线程,从而避免出现以上问题。

(2)使多CPU系统更加有效。当线程数不大于CPU数目时,操作系统可以调度不同的线程运行于不同 的CPU上。

(3)改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为独立或半独立的运行部分, 这样有利于代码的理解和维护。

二、特点

(1)多线程程序的行为无法预期,当多次执行上述程序时,每次的运行结果都可能不同。

(2)多线程的执行顺序无法保证,它与操作系统的调度策略和线程优先级等因素有关。

(3)多线程的切换可能发生在任何时刻、任何地点。

(4)由于多线程对代码的敏感度高,因此对代码的细微修改都可能产生意想不到的结果。

三、简单实例

单击“开始”按钮将启动数个工作线程(工作线程 数目由MAXSIZE宏决定),各个线程循环打印数字0~9,直到单击“停止”按钮终止所有线程为止。具体操作步骤如下:

(1)在头文件“threaddlg.h”中声明用于界面显示所需的控件,其具体代码如下:

#include <QDialog> 
#include <QPushButton> 
class ThreadDlg : public QDialog 
{ 
Q_OBJECT 
public: 
ThreadDlg(QWidget *parent = 0); 
~ThreadDlg(); 
private: 
QPushButton *startBtn; 
QPushButton *stopBtn; 
QPushButton *quitBtn; 
}; 
           

(2)在源文件“threaddlg.cpp”的构造函数中,完成各个控件的初始化工作,其具体代码如下:

#include "threaddlg.h" 
#include <QHBoxLayout> 
ThreadDlg::ThreadDlg(QWidget *parent) 
: QDialog(parent) 
{ 
setWindowTitle(tr("线程")); 
startBtn = new QPushButton(tr("开始")); 
stopBtn = new QPushButton(tr("停止")); 
quitBtn = new QPushButton(tr("退出")); 
QHBoxLayout *mainLayout = new QHBoxLayout(this); 
mainLayout->addWidget(startBtn); 
mainLayout->addWidget(stopBtn); 
mainLayout->addWidget(quitBtn); 
} 
           

(3)此时运行程序,界面显示如下图所示:

QT学习:多线程

以上完成了界面的设计,下面的内容是具体的功能实现。

(1)在头文件“workthread.h”中,工作线程WorkThread类继承自QThread类。重新实现run()函数。其具体代码如下:

#include <QThread> 
class WorkThread : public QThread 
{ 
Q_OBJECT 
public: 
WorkThread(); 
protected: 
void run(); 
}; 
           

(2)在源文件“workthread.cpp”中添加具体实现代码如下:

#include "workthread.h" 
#include <QtDebug> 
WorkThread::WorkThread() 
{
}
           

run()函数实际上是一个死循环,它不停地打印数字0~9。为了显示效果明显,程序将每一个数字重复打印8次。

void WorkThread::run() 
{ 
while(true) 
{ 
for(int n=0;n<10;n++) 
qDebug()<<n<<n<<n<<n<<n<<n<<n<<n; 
} 
} 
           

(3)在头文件“threaddlg.h”中添加以下内容:

#include "workthread.h" 
#define MAXSIZE 1 //MAXSIZE宏定义了线程的数目 
public slots: 
void slotStart(); //槽函数用于启动线程 
void slotStop(); //槽函数用于终止线程 
private: 
WorkThread *workThread[MAXSIZE]; //(a) 指向工作线程(WorkThread)的私有指针数组workThread,记录了所启动的全部线程。
           

(4)在源文件“threaddlg.cpp”中添加以下内容。

在构造函数中添加如下代码:

connect(startBtn,SIGNAL(clicked()),this,SLOT(slotStart())); 
connect(stopBtn,SIGNAL(clicked()),this,SLOT(slotStop())); 
connect(quitBtn,SIGNAL(clicked()),this,SLOT(close())); 
           

当用户单击“开始”按钮时,将调用槽函数slotStart()。这里使用两个循环,目的是使新建的线程尽可能同时开始执行,其具体实现代码如下:

void ThreadDlg::slotStart() 
{ 
for(int i=0;i<MAXSIZE;i++) 
{ 
workThread[i]=new WorkThread(); //创建指定数目的WorkThread线程,并将WorkThread实例的指针保存在指针数组workThread中。 
 
}
for(int i=0;i<MAXSIZE;i++) 
{ 
workThread[i]->start(); //(b) 调用QThread基类的start()函数,此函数将启动run()函数,从而使线程开始真正运行。 

}
startBtn->setEnabled(false); 
stopBtn->setEnabled(true); 
} 
           

当用户单击“停止”按钮时,将调用槽函数slotStop()。其具体实现代码如下:

void ThreadDlg::slotStop() 
{ 
for(int i=0;i<MAXSIZE;i++) 
{ 
workThread[i]->terminate(); 
workThread[i]->wait(); 
}
startBtn->setEnabled(true); 
stopBtn->setEnabled(false); 
} 
           

(5)多线程简单实现结果如下图所示。

QT学习:多线程
QT学习:多线程

第1张图片是启动5个线程的运行结果,第2张图片是启动单一线程的运行结果。可以看出,单一线程的输出是顺序打印的,而多线程的输出结果则是乱序打印的,这正是多线程的一大特点。