一个可重入的类,指的是它的成员函数可以被多个线程安全地调用,只要每个线程使用这个类的不同的对象。而一个线程安全的类,指的是它的成员函数能够被多线程安全地调用,即使所有的线程都使用该类的同一个实例也没有关系。
QObject是可重入的。它的大多数非GUI子类,例如:QTimer、QTcpSocket、QUdpSocket和QProcess,也都是可重入的,这使得在多线程中同时使用这些类成为可能。注意:这些类被设计成在单一线程中创建和使用的,在一个线程中创建一个对象而在另一个线程中调用该对象的函数,不保证能行得通。需要注意有三个约束:
Qt开启多线程,主要用到类QThread。有两种方法,第一种用一个类继承QThread,然后重新改写虚函数run()。当要开启新线程时,只需要实例该类,然后调用函数start(),就可以开启一条多线程。第二种方法是继承一个QObject类,然后利用moveToThread()函数开启一个线程槽函数,将要花费大量时间计算的代码放入该线程槽函数中。
Qt多线程编程注意事项:
关于Qobject类的connect函数最后一个参数,连接类型:
示例代码如下:
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
~MyThread();
protected:
//重写run函数,即线程执行函数
void run();
signals:
//自定义的子线程执行完毕后发出的信号
void isDone();
public slots:
};
#endif // MYTHREAD_H
mywidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include
#include
#include "mythread.h"
namespace Ui {
class MyWidget;
}
class MyWidget : public QWidget
{
Q_OBJECT
public:
explicit MyWidget(QWidget *parent = 0);
~MyWidget();
private slots:
//定时器超时处理槽函数
void dealTimeOut();
void on_pushButton_clicked();
//子线程退出时的处理函数
void dealDone();
//点击右上角红叉进行子线程退出的槽函数
void stopThread();
private:
Ui::MyWidget *ui;
QTimer MyTimer;
MyThread* thread;
};
#endif // MYWIDGET_H
mythread.cpp
#include "mythread.h"
#include
MyThread::MyThread(QObject *parent) : QThread(parent)
{
}
//重写run函数,即线程执行函数
void MyThread::run()
{
int i = 0;
while(i < 10)
{
i++;
sleep(1);
qDebug()<<"我是子线程,我的ID是:"<
mywidget.cpp
#include "mywidget.h"
#include "ui_mywidget.h"
#include
#include
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::MyWidget)
{
ui->setupUi(this);
thread = new MyThread(this);
//关联信号与槽
connect(&this->MyTimer,QTimer::timeout,this,&MyWidget::dealTimeOut);
connect(thread,&MyThread::isDone,this,&MyWidget::dealDone);
connect(this,&MyWidget::destroy,this,&MyWidget::stopThread);
}
void MyWidget::stopThread()
{
//退出
thread->quit();
//等待子进程函数执行完毕后,再退出
thread->wait();
}
void MyWidget::dealDone()
{
MyTimer.stop();
qDebug()<<"子线程is Done";
}
void MyWidget::dealTimeOut()
{
static int i = 0;
i++;
ui->lcdNumber->display(i);
qDebug()<<"我是主线程,我的ID是:"<start();
}
最后运行结果如下:
我是主线程,我的ID是: 0x3f14
我是主线程,我的ID是: 0x3f14
我是主线程,我的ID是: 0x3f14
我是主线程,我的ID是: 0x3f14
我是子线程,我的ID是: 0x36d4
子线程is Done
2、Qt4.6之后的多线程
示例代码如下:
mthread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include
#include
class MyThread : public QObject
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
~MyThread();
//自定义线程处理函数,不能直接调用,否则函数和主线程在一个线程内,
//如果该函数有耗时操作,线程将会卡死
void myTimeOut();
signals:
//自定义信号,用来通知主线程进行相关操作
void mysignals();
public:
bool isStop;
public slots:
};
#endif // MYTHREAD_H
mywidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include
#include "mythread.h"
namespace Ui {
class MyWidget;
}
class MyWidget : public QWidget
{
Q_OBJECT
public:
explicit MyWidget(QWidget *parent = 0);
~MyWidget();
signals:
void myStartThread();
private slots:
//启动按钮的回调函数
void on_startBtn_clicked();
//停止按钮的回调函数
void on_pushButton_2_clicked();
//处理子进程的槽函数
void dealSignals();
//退出程序时的槽函数
void stopThread();
private:
//自定义线程类对象
MyThread* mythread;
//线程类对象
QThread* thread;
Ui::MyWidget *ui;
};
#endif // MYWIDGET_H
mypthread.cpp
#include "mythread.h"
#include
MyThread::MyThread(QObject *parent) : QObject(parent)
{
isStop = false;
}
MyThread::~MyThread()
{
}
void MyThread::myTimeOut()
{
while(!isStop)
{
qDebug()<<"我是子线程,我的ID是:"<
mywidget.cpp
#include "mywidget.h"
#include "ui_mywidget.h"
#include
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::MyWidget)
{
ui->setupUi(this);
//动态分配空间,不可以指定父对象
mythread = new MyThread;
//创建子线程
thread = new QThread(this);
//将自定义线程加入到子线程中去,即指定子线程位自定义线程的父亲
mythread->moveToThread(thread);
//建立主线程与子线程的信号与槽
connect(mythread,&MyThread::mysignals,this,&MyWidget::dealSignals);
//通过信号与槽方式,调用子线程的线程处理函数
connect(this,&MyWidget::myStartThread,mythread,&MyThread::myTimeOut);
//关闭操作时,进行线程退出操作
connect(this,&MyWidget::destroyed,this,&MyWidget::stopThread);
qDebug()<<"我是主线程,我的ID是:"<isRunning())
{
mythread->isStop = true;
thread->quit();
thread->wait();
}
}
//主线程根据子线程信号进行槽函数操作
void MyWidget::dealSignals()
{
static int i = 0;
i++;
ui->lcdNumber->display(i);
}
MyWidget::~MyWidget()
{
delete ui;
}
//启动按钮的槽函数
void MyWidget::on_startBtn_clicked()
{
if(false == thread->isRunning())
{
//启动子线程,但是不启动自定义线程的处理函数
thread->start();
mythread->isStop = false;
emit myStartThread();
}
}
//停止按钮的槽函数
void MyWidget::on_pushButton_2_clicked()
{
if(thread->isRunning())
{
mythread->isStop = true;
thread->quit();
thread->wait();
}
}
代码运行结果如下:
我是主线程,我的ID是: 0x19e0
我是子线程,我的ID是: 0x4430
我是子线程,我的ID是: 0x4430