提要
Qt对线程提供了支持,基本形式有独立于平台的线程类、线程安全方式的事件传递和一个全局Qt库互斥量允许你可以从不同的线程调用Qt方法。
每个程序启动后就会拥有一个线程。该线程称为”主线程”(在Qt应用程序中也叫”GUI线程”)。Qt GUI必须运行在此线程上。所有的图形元件和几个相关的类,如QPixmap,不能工作于非主线程中。非主线程通常称为”工作者线程”,因为它主要处理从主线程中卸下的一些工作。
有时候,你需要的不仅仅是在另一线程的上下文中运行一个函数。您可能需要有一个生存在另一个线程中的对象来为 GUI线程提供服务。也许你想在另一个始终运行的线程中来轮询硬件端口并在有关注的事情发生时发送信号到GUI线程。Qt为开发多线程应用程序提供了多种 不同的解决方案。解决方案的选择依赖于新线程的目的以及线程的生命周期。
环境
Ubuntu 12.04 64bit
Qt 4.8.1
一个简单的例子
首先来看一个单线程的例子。
用Qt Creator创建一个Qt Gui工程,只有一个mainwindow类,代码如下:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include
#include
class MainWindow : public QMainWindow { Q_OBJECT private: QPushButton *calButton; QPushButton *hiButton; QLabel *mLabel; public: MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void slotGetPi(); void slotSayHi(); }; #endif // MAINWINDOW_H
mainwindow.cpp
#include mainwindow.h
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QHBoxLayout *mainLayout=new QHBoxLayout();
calButton = new QPushButton(this);
calButton->setText(GetPi);
hiButton = new QPushButton(this);
hiButton->setText(Hi);
mLabel = new QLabel();
mLabel->setText(Bitch);
mainLayout->setSpacing(10);
mainLayout->addWidget(calButton);
mainLayout->addWidget(hiButton);
mainLayout->addWidget(mLabel);
QWidget *centreWidget=new QWidget(this);
centreWidget->setLayout(mainLayout);
this->setCentralWidget(centreWidget);
this->connect(calButton,SIGNAL(released()),this, SLOT(slotGetPi()));
this->connect(hiButton,SIGNAL(released()),this, SLOT(slotSayHi()));
}
MainWindow::~MainWindow()
{
}
void MainWindow::slotGetPi()
{
int time = 1000000000;
float result=0;
for(int i=1;i<=time;i++)
{
double value=4.0/(2*i-1);
if (i % 2 == 1) result+=value;
else result-=value;
}
mLabel->setText(QString::number(result));
}
void MainWindow::slotSayHi()
{
mLabel->setText(Hei,gay~);
}
main.cpp
#include
#include mainwindow.h
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
代码很简单,就是一个窗口中有两个Button和一个label, 一个Button计算Pi,一个Button say hi 两个button都可以更新label.
预记的运行效果是点击button之后就可以改变label的值,但实际情况是...

因为我在点击GetPi这个Button的时候,程序就开始计算,当然是在主线程中,这时候整个界面就阻塞了,Hi Button 设置关闭窗口操作都无法完成,这时就不得不用线程了。
用线程改写一下。
创建一个ComputeThread类,继承自QThread。
computethread.h
#ifndef COMPUTETHREAD_H
#define COMPUTETHREAD_H
#include
#include
#include
class ComputeThread : public QThread { Q_OBJECT private: void run(); public: explicit ComputeThread(QObject *parent = 0); signals: void computeFinish(double result); public slots: }; #endif // COMPUTETHREAD_H
computethread.cpp
#include computethread.h
ComputeThread::ComputeThread(QObject *parent) :
QThread(parent)
{
}
void ComputeThread::run()
{
qDebug()<
currentThreadId()<<:Begin computing!<
computeFinish(result); }
在run中定义线程运行的内容,还定义了一个信号,在计算完毕的时候将结果发射出去。
mainwindow中添加一个ComputeThread对象和一个槽。
private:
ComputeThread *computePiThread;
private slots:
void slotShowResult(double result);
cpp中加入线程操作的部分:
#include mainwindow.h
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QVBoxLayout *mainLayout=new QVBoxLayout();
calButton = new QPushButton(this);
calButton->setText(GetPi);
hiButton = new QPushButton(this);
hiButton->setText(Hi);
mLabel = n