Qt-线程的使用
1 简介
参考视频:https://www.bilibili.com/video/BV1XW411x7NU?p=74
使用多线程的好处:提高应用程序响应速度、使多CPU更加高效、改善程序结构。
在Qt中使用QThread来管理线程。Qt中使用线程时,需要自己实现一个thread的类。
2 测试说明
(1)基本使用
功能说明如下:

工程文件有:

mythread.h和mythread.cpp是自定义的线程类,需要改为继承自QThread,QThread类有一个虚函数run(),它就是线程处理函数,我们需要重写它。
当我们调用QThread的start()函数时,会间接的调用run()函数。
widget.h和widget.cpp是主窗口的代码。
mythread.h的代码:

#ifndef MYTHREAD_H
#define MYTHREAD_H #include <QObject>
#include <QThread> class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = nullptr); signals:
void isDone(); protected:
//QThread的虚函数,线程处理函数
//不能直接调用,通过start()间接调用
void run(); public slots:
}; #endif // MYTHREAD_H
mythread.cpp代码:

#include "mythread.h" MyThread::MyThread(QObject *parent) : QThread(parent)
{ } void MyThread::run()
{
//很复杂的数据处理,需要耗时5s
sleep();
//发送处理完成信号
emit isDone();
}
widget.h代码:

#ifndef WIDGET_H
#define WIDGET_H #include <QWidget>
#include <QTimer> //定时器
#include "mythread.h" //线程 namespace Ui {
class Widget;
} class Widget : public QWidget
{
Q_OBJECT public:
explicit Widget(QWidget *parent = );
~Widget(); void dealTimeout(); //定时器处理函数
void dealThread(); //处理子线程发来的信号
void stopThread(); //停止线程 private slots:
void on_pushButton_start_clicked(); private:
Ui::Widget *ui; QTimer *timer = NULL;
MyThread *thread = NULL;
}; #endif // WIDGET_H
widget.cpp代码:

#include "widget.h"
#include "ui_widget.h"
#include <QThread>
#include <QDebug> Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this); timer = new QTimer(this);
//分配空间
thread = new MyThread(this); //只要定时器启动,自动触发timerout()信号
connect(timer, &QTimer::timeout, this, &Widget::dealTimeout);
//接收子线程发送的isDone信号并处理
connect(thread, &MyThread::isDone, this, &Widget::dealThread);
//当按窗口右上角x时(关闭窗口),触发
connect(this, &Widget::destroyed, this, &Widget::stopThread);
} Widget::~Widget()
{
delete ui;
} void Widget::dealTimeout()
{
static int i = ;
i++;
//设定lcd的值
ui->lcdNumber->display(i);
} void Widget::dealThread()
{
//处理完数据后,关闭定时器
timer->stop();
qDebug() << "timer turn off!!!";
} void Widget::stopThread()
{
//停止线程
thread->quit();
//等待线程处理完事情
thread->wait();
} void Widget::on_pushButton_start_clicked()
{
if (timer->isActive() == false) {
timer->start();
}
//启动线程,处理数据
thread->start();
}
运行测试:

可以看到计数了45次之后(每次100ms),定时器停止了,表示接收到了线程发送的信号(线程睡眠5s之后发出的)。可能会有疑问为什么不是50次(刚好5s),那是因为我们先启动定时器,在去启动线程,这个过程需要花费时间。
(2)多线程的使用
多线程的实现模型如下,记下来就好了:

先给出实现的代码,后面再介绍。
工程文件有:

mythread.h和mythread.cpp是自定义的线程类,继承自QThread,和前一个例子不一样。
widget.h和widget.cpp是主窗口的代码。
mythread.h代码:

#ifndef MYTHREAD_H
#define MYTHREAD_H #include <QObject> class MyThread : public QObject
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = nullptr); //线程处理函数
void myTimerout();
//设置flag,用于判断是否结束线程处理函数的while循环
void setFlag(bool flag = true); signals:
void mySignal(); public slots: private:
bool isStop;
}; #endif // MYTHREAD_H
mythread.c代码:

#include "mythread.h"
#include <QThread>
#include <QDebug> MyThread::MyThread(QObject *parent) : QObject(parent)
{
isStop = false;
} void MyThread::myTimerout()
{
while (isStop == false) {
QThread::sleep();
emit mySignal();
qDebug() << "子线程号:" << QThread::currentThread();
if (true == isStop) {
break;
}
}
} void MyThread::setFlag(bool flag)
{
isStop = flag;
}
widget.h代码:

#ifndef WIDGET_H
#define WIDGET_H #include <QWidget>
#include "mythread.h"
#include <QThread> namespace Ui {
class Widget;
} class Widget : public QWidget
{
Q_OBJECT public:
explicit Widget(QWidget *parent = );
~Widget(); void dealsignal();
void dealclose();
signals:
//启动子线程的信号
void startThreadSignal(); private slots:
void on_pushButton_start_clicked(); void on_pushButton_stop_clicked(); private:
Ui::Widget *ui;
MyThread *mythread = NULL;
QThread *thread = NULL;
}; #endif // WIDGET_H
widget.cpp代码:

#include "widget.h"
#include "ui_widget.h"
#include <QDebug> Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//动态分配空间,不能指定父对象
mythread = new MyThread;
//创建子线程
thread = new QThread(this);
//把自定义的线程加入到子线程中
mythread->moveToThread(thread); //处理子线程发送的信号
connect(mythread, &MyThread::mySignal, this, &Widget::dealsignal);
qDebug() << "主线程号:" << QThread::currentThread();
//发送信号给子线程,通过信号和槽调用子线程的线程处理函数
connect(this, &Widget::startThreadSignal, mythread, &MyThread::myTimerout);
//关闭主窗口
connect(this, &Widget::destroyed, this, &Widget::dealclose);
} Widget::~Widget()
{
delete ui;
} void Widget::dealsignal()
{
static int i = ;
i++;
ui->lcdNumber->display(i);
} void Widget::dealclose()
{
mythread->setFlag(true);
thread->quit();
thread->wait();
delete mythread;
} void Widget::on_pushButton_start_clicked()
{
if (thread->isRunning() == true) {
return;
}
//启动线程,但是没有启动线程处理函数
thread->start();
mythread->setFlag(false);
//不能直接调用线程处理函数
//直接调用导致线程处理函数和主线程在同一个线程
//只能通过信号和槽调用
emit startThreadSignal();
} void Widget::on_pushButton_stop_clicked()
{
if (thread->isRunning() == false) {
return;
}
mythread->setFlag(true);
thread->quit();
thread->wait();
}
需要说明以下几点:
(1)创建自定义线程变量时,不能指定父对象(mythread=newMyThread;),因为调用moveToThread函数之后,变量在创建的线程中使用回收,而不是在主线程。
(2)子线程会睡眠1s就发送一个信号mySignal给主线程,主线程接收信号,在槽函数中将数值累加一,并在LCD上显示。
(3)主线程通过信号和槽的方式调用子线程处理函数,主线程发送信号给子线程,槽函数就是子线程的线程处理函数。
(4)子线程setFlag()的作用是:关闭子线程时,quit()函数会等待子线程执行结束之后再回收,但是如果不设置标志,while循环会一直执行,子线程也就没有结束。
运行测试:

注意看打印的信息,可以看到子线程和主线程的id。
Qt-线程的使用的更多相关文章
- Qt线程(2) QThread中使用WorkObject
一般继承QThread的WorkThread都会在重载的run()中创建临时的WorkObject,这样能确定这个WorkObject在该thread中使用 那如果这个WorkObject是个Sing ...
- 详解 Qt 线程间共享数据(用信号槽方式)
使用共享内存.即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的. Qt 线程间共享数据是本文介绍的内容,多的不说,先来啃内容.Qt线程间共享 ...
- Qt线程(1) moveToThread
若在Qt准备使用线程类一般有两种方式(1) 采用WorkObject配合QThread进行使用 (2)继承QThread, 重载run()函数即可. 注:采用Qt::Concurrent之类的不在本文 ...
- QT核心编程之Qt线程 (c)
QT核心编程之Qt线程是本节要介绍的内容,QT核心编程我们要分几个部分来介绍,想参考更多内容,请看末尾的编辑推荐进行详细阅读,先来看本篇内容. Qt对线程提供了支持,它引入了一些基本与平台无关的线程类 ...
- QT线程(一):线程类
线程之间共享数据,但又单独执行: QT线程QThread是平台无关的: 通常主线程从main开始执行,而在主线程中创建其他线程,其他线程派生于QThread: 1.线程优先级 总共8个优先级:线程 ...
- Qt 线程基础(Thread Basics的翻译,线程的五种使用情况)
Qt 线程基础(QThread.QtConcurrent等) 转载自:http://blog.csdn.net/dbzhang800/article/details/6554104 昨晚看Qt的Man ...
- Qt 学习之路 :Qt 线程相关类
希望上一章有关事件循环的内容还没有把你绕晕.本章将重新回到有关线程的相关内容上面来.在前面的章节我们了解了有关QThread类的简单使用.不过,Qt 提供的有关线程的类可不那么简单,否则的话我们也没必 ...
- Qt 线程基础(QThread、QtConcurrent等)
[-] 使用线程 何时使用其他技术替代线程 应该使用 Qt 线程的哪种技术 Qt线程基础 QObject与线程 使用互斥量保护数据的完整 使用事件循环防止数据破坏 处理异步执行 昨晚看Qt的Manua ...
- Qt 线程基础
(转自:http://my.oschina.net/laopiao/blog/88158) 何谓线程? 线程与并行处理任务息息相关,就像进程一样.那么,线程与进程有什么区别呢?当你在电子表格上进行数据 ...
- Qt 学习之路 2(73):Qt 线程相关类
Home / Qt 学习之路 2 / Qt 学习之路 2(73):Qt 线程相关类 Qt 学习之路 2(73):Qt 线程相关类 豆子 2013年11月26日 Qt 学习之路 2 7条评论 希 ...
随机推荐
- Spring AOP学习笔记03:AOP的核心实现之获取增强器
上文讲了spring是如何开启AOP的,简单点说就是将AnnotationAwareAspectJAutoProxyCreator这个类注册到容器中,因为这个类最终实现了BeanPostProcess ...
- 使用vscode 开发go项目的最新姿势. go版本1.14.2
使用了go 1.14.2. 版本, 再也不用建src, pkg, bin 目录了, 以及再也不用强制配置GOPATH了 前提条件: 必须是 go mod 项目. 在工程目录下, 执行这样的命令生成 ...
- C#数据结构与算法系列(十):中缀表达式转后缀表达式
1.具体步骤 1)初始化两个栈:运算符栈s1和储存中间结果的栈s2:2)从左至右扫描中缀表达式:3)遇到操作数时,将其压s2:4)遇到运算符时,比较其与s1栈顶运算符的优先级: (1)如果s1 ...
- SpringCloud 入门(一)
本人也是刚接触springcloud,现在先将创建项目的过程记录下来,springcloud的理解日后再慢慢补齐,最好还是自己参考官方文档的介绍 使用工具:IDEA IDEA创建springcloud ...
- JavaScript基础Literal 与 Constructor(008)
JavaScript支持以字面声名法(Literal)的方式来声名对象和数组,相对于构造函数(constructor)的方式,Literal的声 名方式更简洁,更易读,也更少导致Bug.事实上,JSO ...
- 谈谈如何绕过 TinyPNG 对上传图片数量的限制
前端er, 又称为切图仔,平时经常需要用 PSD 导出 PNG 或 JPG,但是导出来的的图片一般比较大,往往需要用一些其他工具压缩后再发布到生产环境. 以前常用的做法是,使用 image-webpa ...
- 学习 Java 网站推荐给你
推荐几个非常不错的 Java 学习网站 LearnJava 在线 这是一个非常不错的学习 Java 的在线网站,纯免费.这是一个个人项目,旨在通过简单有效的在浏览器中进行练习让你快速掌握 Java 编 ...
- MySQL实验 内连接优化order by+limit 以及添加索引再次改进
MySQL实验 内连接优化order by+limit 以及添加索引再次改进 在进行子查询优化双参数limit时我萌生了测试更加符合实际生产需要的ORDER BY + LIMIT的想法,或许我们也可以 ...
- salesman,动态规划带一点点贪心。
题目直接链接 分析一下: 这题题意还是比较明白的(少见的一道中文题),他的意思就是:有这么一个无向图:保证联通且点与点直接有唯一的简单路径(说白了就是棵树,根节点是1),每个节点有一个权值(有正有负) ...
- Kafka入门(1):概述
摘要 在本文中,我将从为什么需要消息队列开始讲起,举两个小例子,跟你聊聊目前消息队列的一些使用场景. 比如消息队列在复杂系统中的解耦,又比如消息队列在高并发下的场景如果让流量变得更平缓. 随后我会跟你 ...