一、QT中的线程
QT中的线程主要是通过QThread进行管理,一个QThread对象管理程序中的一个线程。 QThreads管理的线程在run()中开始执行。 默认情况下,run()通过调用exec()启动并在线程中运行事件循环。
线程的启动方式有两种:
1.使用moveToThread启动线程
示例
//头文件
#ifndef THREADSTART_H
#define THREADSTART_H
#include <QObject>
#include <QThread>
#include <iostream>
#include <cassert>
using namespace std;
class work : public QObject
{
Q_OBJECT
public:
explicit work(QObject *parent = nullptr);
virtual ~work();
public slots:
void dowork();
signals:
void emitsignal();
};
class control:public QObject
{
Q_OBJECT
public:
explicit control(QObject *parent=nullptr);
virtual ~control();
public slots:
void signalhandler();
signals:
void worksignal();
private:
QThread workthread_;
};
#endif // THREADSTART_H
//源文件
#include "threadstart.h"
work::work(QObject *parent) : QObject(parent)
{
cout<<__func__<<endl;
}
work::~work()
{
cout<<__func__<<endl;
}
void work::dowork()
{
while(1) {
QThread::sleep(1);
cout<<__func__<<QThread::currentThreadId()<<endl;
emit emitsignal();
}
}
control::control(QObject *parent):QObject(parent)
{
work *pwork=new work();
pwork->moveToThread(&workthread_);//将pwork指向的对象移动到目标线程workthread_中
connect(&workthread_, &QThread::finished, pwork, &QObject::deleteLater);
connect(this, &control::worksignal, pwork, &work::dowork);
connect(pwork, &work::emitsignal, this, &control::signalhandler);
workthread_.start();//start内部会调用run函数启动一个线程,如果不重新run函数,run函数默认执行exec
emit worksignal();
}
control::~control()
{
cout<<__func__<<endl;
workthread_.quit();
workthread_.wait();
}
void control::signalhandler()
{
cout<<__func__<<QThread::currentThreadId()<<endl;
cout<<"received signal"<<endl;
}
//主函数
#include <QCoreApplication>
#include "threadstart.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
cout<<QThread::currentThreadId()<<endl;
control cl;
return a.exec();
}
上述程序输出结果如下
上述代码的思路就是在主线程中创建一个QThread对象,然后将工作函数放在该QThread对象对象中去执行,当主线程发出worksignal时,会调用工作线程中的槽函数,在工作线程的槽函数中,又会发射新的信号emitsignal,最后回到主线程中调用槽函数
2.继承QThread
示例
//头文件
#ifndef THREADSTART2_H
#define THREADSTART2_H
#include <QObject>
#include <QThread>
#include <iostream>
#include <cassert>
using namespace std;
class threadstart2 : public QObject
{
Q_OBJECT
public:
explicit threadstart2(QObject *parent = nullptr);
virtual ~threadstart2();
public slots:
void handlesignals();
};
class workthread:public QThread
{
Q_OBJECT
public:
workthread();
virtual ~workthread();
protected:
void run() override;
signals:
void emitsignal();
};
#endif // THREADSTART2_H
//源文件
#include "threadstart2.h"
threadstart2::threadstart2(QObject *parent) : QObject(parent)
{
workthread *wt=new workthread();
connect(wt, &workthread::emitsignal, this, &threadstart2::handlesignals);
wt->start();
}
threadstart2::~threadstart2()
{
cout<<__func__<<endl;
}
void threadstart2::handlesignals()
{
cout<<__func__<<endl;
}
workthread::workthread() : QThread()
{
cout<<__func__<<endl;
}
workthread::~workthread()
{
cout<<__func__<<endl;
}
void workthread::run()
{
while(1) {
QThread::sleep(1);
emit emitsignal();
cout<<QThread::currentThreadId()<<endl;
}
}
//主函数
#include <QCoreApplication>
#include "threadstart2.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
cout<<QThread::currentThreadId()<<endl;
threadstart2 ts2;
return a.exec();
}
示例代码的思路就是定义一个继承QThread的类并重写run函数,然后在主线程中实例化该类并启动线程,最后执行run函数并发出信号
这种线程的启动方式和第一种方式有一个区别,就是信号对应的槽函数在主线程中执行而不在新线程中执行
原因是因为:一个QThread实例位于实例化它的旧线程中,而不位于调用run函数的新线程中。 所以,所有QThread排队执行的槽函数也都将在旧线程中执行。
因此,如果想在新线程中调用槽函数,请使用第一种方式启动QT的线程。
参考
https://doc.qt.io/qt-5/qthread.html#details
欢迎大家评论交流,作者水平有限,如有错误,欢迎指出