QThread线程学习笔记

时间:2022-09-04 19:35:43

1、QT版本

QT5.1

2、下面的测试程序在QtCreator的Qt Gui应用(QDialog)模板修改而成

3、下面是测试代码

头文件

#ifndef DIALOG_H
#define DIALOG_H
 
#include <QDialog>
#include <QThread>
#include <QTimer>
class Object;
class Thread : public QThread
{
 Q_OBJECT
public:
 Thread(QObject *parent = 0);
Q_SIGNALS:
 void signalA();
private slots:
 void slotB();
 void slotT(); //响应定时器的槽
private:
 void run();
 //定义为类成员与在run()函数中定义该对象指针对线程执行没影响
 Object *object;
 QTimer *t;
};
 
 
class Object : public QObject
{
 Q_OBJECT
public:
 Object(QObject *parent =0);
public slots:
 void slotT();//响应定时器的槽
};
 
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
 Q_OBJECT
 
public:
 explicit Dialog(QWidget *parent = 0);
 ~Dialog();
 
Q_SIGNALS:
 void signalB();
 
private slots:
 void slotA();
 void slotBtnA();//响应按键ui->pushbutton
 
private:
 Ui::Dialog *ui;
 Thread *thread ;
};
 
#endif // DIALOG_H
 

源文件

#include "dialog.h"
#include "ui_dialog.h"
#include <QDebug>
 
Dialog::Dialog(QWidget *parent) :
 QDialog(parent),
 ui(new Ui::Dialog)
{
 ui->setupUi(this);
 thread = new Thread(this);
 connect(thread, SIGNAL(signalA()), this, SLOT(slotA()));
// connect(this, SIGNAL(signalB()), thread, SLOT(slotB()));
 connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(slotBtnA()));
 qDebug()<<"Dialog Thread ID : "<<QThread::currentThreadId();
}
 
Dialog::~Dialog()
{
 delete ui;
}
 
void Dialog::slotA()
{
 qDebug()<<"Dialog::slotA Thread ID : "<<QThread::currentThreadId();
}
 
void Dialog::slotBtnA()
{
 Q_EMIT(signalB());
}
 
Thread::Thread(QObject *parent):
 QThread(parent)
{ //在构造函数定义(new)的对象都属于界面线程(主线程),下面测试的对象都在run()函数体里构建
 start();
}
 
void Thread::run()
{
 QTimer *t = new QTimer();
 object = new Object();
/*
 *object = new Object(this); 这样创建将会报警:
 *QObject: Cannot create children for a parent that is in a different thread.
 *(Parent is Thread(0x3dcea8), parent's thread is QThread(0x11fbe8d0), current thread is Thread(0x3dcea8)
 *但程序可以运行,且下面定时器响应槽slotT()是在子线程执行的
*/
 connect(t, SIGNAL(timeout()), this, SLOT(slotT()));//由于this这个对象属于主线程,故它的槽slotT是有主线程执行
 connect(t, SIGNAL(timeout()), object, SLOT(slotT())); //同理object在子线程创建,故它的槽slotT是由子线程执行
 t->start(3000);
 Dialog *parentDlg = qobject_cast<Dialog*>(parent());
 connect(parentDlg, SIGNAL(signalB()), this, SLOT(slotB()));//这个同上面一样,有主线程执行槽
 qDebug()<<"Sub Thread ID : "<<QThread::currentThreadId();
 Q_EMIT(signalA());
 exec();
}
 
 
void Thread::slotB()
{
 qDebug()<<"Thread::slotB Thread ID : "<<QThread::currentThreadId();
}
 
void Thread::slotT()
{
 qDebug()<<"Thread::slotT Thread ID : "<<QThread::currentThreadId();
}
 
 
void Object::slotT()
{
 qDebug()<<"Object::slotT Thread ID : "<<QThread::currentThreadId();
}


Object::Object(QObject *parent):
 QObject(parent)
{
}
 

 

由此可总结出:

1)、子类化QThread的类的构造函数,创建它的线程执行,创建出的对象(thread),属于创建它的那个线程;

2)、两线程通过信号与槽通信,槽函数由哪个线程执行,主要看其对象属于哪个线程(即创建它的那个线程),和connect的调用位置无关

3)、在子线程中创建对象时,主要避免使用父线程创建的对象作为父对象

 

 为了在子线程中处理耗时逻辑,使用上面这种信号和槽的连接方法,虽然可用,但连接的信号和槽太多,太乱,特别是子线程还要返回执行结果的情况下,又要定义一组信号和槽。所以可以使用

QMetaObject::invokeMethod
 

void MainWindow::slotBtnClick()
{
 int retVal = 0;
 int a = 1;
 int b = 1;
 //QMetaMethod::invoke: Unable to invoke methods with return values in queued connections
 //bool bInvoke = QMetaObject::invokeMethod(&m_thread, "slotAdd", Qt::AutoConnection, Q_RETURN_ARG(int, retVal), Q_ARG(int, a), Q_ARG(int, b));
 //bool bInvoke = QMetaObject::invokeMethod(&m_thread, "slotAdd", Qt::QueuedConnection, Q_RETURN_ARG(int, retVal), Q_ARG(int, a), Q_ARG(int, b));
 bool bInvoke = QMetaObject::invokeMethod(&m_thread, "slotAdd", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, retVal), Q_ARG(int, a), Q_ARG(int, b));
 
 qDebug()<<"QMetaObject::invokeMethod "<<bInvoke<<" a+b= "<<retVal;
 qDebug()<<"MainWindow::slotBtnClick() Thread ID : "<<QThread::currentThreadId();
}
注意:线程间调用只有BlockingQueuedConnection才可以使用返回值

int Thread::slotAdd(int a, int b)
{
 int c = a + b;
 qDebug()<<"Thread::slotAdd Thread ID : "<<QThread::currentThreadId();
 return c;
}
 

 结果

Thread::run() Thread ID : 0x1e08

Thread::slotAdd Thread ID : 0x1e08

QMetaObject::invokeMethod true a+b= 2

MainWindow::slotBtnClick() Thread ID : 0x3310