qt实现多线程的方式大致分为两种:
1. 直接继承自QThread,重写run函数
2. 继承QObject,通过 moveToThread将事件添加到线程中处理
第一种方式:
#include "mythread.h"
#include <QDebug>
#include <QMutex>
MyThread::MyThread()
{
isStop = false;
}
void MyThread::closeThread()
{
isStop = true;
}
void MyThread::run()
{
while (1)
{
if(isStop)
return;
qDebug()<<tr("mythread QThread::currentThreadId()==")<<QThread::currentThreadId();
sleep(1);
}
}
#include "widget.h"
#include <QDebug>
#include <windows.h>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
createView();
}
void Widget::createView()
{
/*添加界面*/
QPushButton *openThreadBtn = new QPushButton(tr("打开线程"));
QPushButton *closeThreadBtn = new QPushButton(tr("关闭线程"));
mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(openThreadBtn);
mainLayout->addWidget(closeThreadBtn);
mainLayout->addStretch();
connect(openThreadBtn,SIGNAL(clicked(bool)),this,SLOT(openThreadBtnSlot()));
connect(closeThreadBtn,SIGNAL(clicked(bool)),this,SLOT(closeThreadBtnSlot()));
/*线程初始化*/
thread1 = new MyThread;
connect(thread1,SIGNAL(finished()),this,SLOT(finishedThreadBtnSlot()));
}
void Widget::openThreadBtnSlot()
{
/*开启一个线程*/
thread1->start();
qDebug()<<"主线程id:"<<QThread::currentThreadId();
}
void Widget::closeThreadBtnSlot()
{
/*关闭多线程*/
thread1->closeThread();
thread1->wait();
}
void Widget::finishedThreadBtnSlot()
{
qDebug()<<tr("完成信号finished触发");
}
Widget::~Widget()
{
}
采用第一种方法会有一个问题:重写run函数后,线程的默认事件循环不会启动,如果有信号从别的线程发送到该线程,那么该线程的槽函数并不会在这个线程中执行,而是由该线程所依赖的线程执行(一般是main线程),这导致了槽函数(slot)和run函数不在同一个线程,所以需要加 QMutex 锁住。
这样就很麻烦,这个问题有三个解决方案:
1. 在自定义QThread中添加,moveToThread(this),这样槽函数就会在该线程中进行了。(这种方法不建议使用)
2. 采用直接连接方式,即信号发出和接收都在自定义QThread中进行。
3. 采用第二种方法:继承QObject类,通过moveToThread将事件添加到线程中处理。这种方法可以直接将槽函数与自定义QThread关联。
第二种方法:
#include "mythread.h"
#include <QDebug>
#include <QThread>
MyThread::MyThread(QObject *parent) : QObject(parent)
{
isStop = false;
}
void MyThread::closeThread()
{
isStop = true;
}
void MyThread::startThreadSlot()
{
while (1)
{
if(isStop)
return;
qDebug()<<"MyThread::startThreadSlot QThread::currentThreadId()=="<<QThread::currentThreadId();
QThread::sleep(1);
}
}
#include <QDebug>
#include "widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
createView();
}
Widget::~Widget()
{
}
void Widget::createView()
{
/*UI界面*/
mainLayout = new QVBoxLayout(this);
QPushButton *openThreadBtn = new QPushButton(tr("打开线程"));
QPushButton *closeThreadBtn = new QPushButton(tr("关闭线程"));
mainLayout->addWidget(openThreadBtn);
mainLayout->addWidget(closeThreadBtn);
mainLayout->addStretch();
connect(openThreadBtn,SIGNAL(clicked(bool)),this,SLOT(openThreadSlot()));
connect(closeThreadBtn,SIGNAL(clicked(bool)),this,SLOT(closeThreadSlot()));
}
void Widget::openThreadSlot()
{
/*开启一条多线程*/
qDebug()<<tr("开启线程");
firstThread = new QThread; //线程容器
myObjectThread = new MyThread;
myObjectThread->moveToThread(firstThread); //将创建的对象移到线程容器中
connect(firstThread,SIGNAL(finished()),myObjectThread,SLOT(deleteLater())); //终止线程时要调用deleteLater槽函数
connect(firstThread,SIGNAL(started()),myObjectThread,SLOT(startThreadSlot())); //开启线程槽函数
connect(firstThread,SIGNAL(finished()),this,SLOT(finishedThreadSlot()));
firstThread->start(); //开启多线程槽函数
qDebug()<<"mainWidget QThread::currentThreadId()=="<<QThread::currentThreadId();
}
void Widget::closeThreadSlot()
{
qDebug()<<tr("关闭线程");
if(firstThread->isRunning())
{
myObjectThread->closeThread(); //关闭线程槽函数
firstThread->quit(); //退出事件循环
firstThread->wait(); //释放线程槽函数资源
}
}
void Widget::finishedThreadSlot()
{
qDebug()<<tr("多线程触发了finished信号123");
}
推荐用法:第二种方法 ,因为这种方法在使用信号和槽时根本不用考虑多线程的存在。也不用使用QMutex来进行同步,Qt的事件循环会自己自动处理好这个。总之就是很简单方便。
{{ cmt.username }}
{{ cmt.content }}
{{ cmt.commentDate | formatDate('YYYY.MM.DD hh:mm') }}