Qt多线程编程
时间:2022-07-24
本文章向大家介绍Qt多线程编程,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
我在github仓库里面看到之前遗留的Qt_Demo,把文章相应的工程文件提交到仓库里面去,上次的简易聊天室
也同步过去了,以及这篇文章的两个线程Demo。
给我个Star
https://github.com/ADeRoy/Qt_Demo
多线程开发
线程基础
GUI线程与工作线程
每个程序启动后拥有的第一个线程称为主线程
,即GUI线程
。QT中所有的组件类和几个相关的类只能工作在GUI线程,不能工作在次线程,次线程
即工作线程
,主要负责处理GUI线程卸下的工作。
什么时候用到多线程?
以界面为例:所有的IO操作
都要放到线程里面
- IO操作
QIODevice
文件IO网络IO
(套接字 eg:CAN linux下也是套接字)串口
等外设 ;因为不确定什么时候能读写完成 - 耗时的算法 eg:
文件压缩
信号处理
注意
线程里面尽量少用 while(1) + sleep(),尤其是while
eg:第一个例子如果用while(1),那么当线程exit(),并等待退出时wait()时不会退出线程,等待超时后会报错
QThread介绍
QThread类
提供了一个与平台无关的管理线程的方法。一个QThread对象管理一个线程。QThread的执行从run()函数的执行开始,在Qt自带的QThread
类中,run()函数通过调用exec()
函数来启动事件循环机制,并且在线程内部处理Qt的事件。在Qt中建立线程的主要目的就是为了用线程来处理那些耗时的后台操作,从而让主界面能及时响应用户的请求操作
。QThread的使用方法有如下两种:
- QObject::moveToThread()
- 继承QThread类
继承QThread类
程序运行后开启线程,打印100~0
Program右键添加新文件,继承QThread
添加头文件
#include <QObject>
#include <QThread>
添加宏
不添加Q_OBJECT宏无法使用信号与槽机制
Q_OBJECT
重写run函数
protected:
virtual void run();
mythread.h文件:
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QObject>
#include <QThread>
class MyThread : public QThread
{
Q_OBJECT
public:
MyThread();
protected:
virtual void run();
private:
};
#endif // MYTHREAD_H
mythread.cpp
#include "mythread.h"
#include <QtDebug>
MyThread::MyThread()
{
/*MyThread的构造函数任然在主线程里面*/
qDebug()<<"MyThread::MyThread:"<<QThread::currentThreadId();
}
void MyThread::run()
{
while(1)
{
qDebug()<<"MyThread::run:"<<QThread::currentThreadId();
QThread::sleep(1);
}
}
main.c
#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include "mythread.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug()<<"main a.exec() :"<<QThread::currentThreadId();
MyThread thread1;
thread1.start();
/*使用线程只需要再次定义线程类MyThread即可*/
// MyThread thread2;
// thread2.start();
return a.exec();
}
QObject::moveToThread()
这里有一个小示例
创建的是带界面的mainwindow窗口
Program右键添加新文件,继承QObject
2
MyThread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QObject>
class MyThread : public QObject
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = nullptr);
signals:
//线程向外部发出带Val值得信号
void SendVal(int);
public slots:
//线程工作函数
void MyThreadWork();
};
#endif // MYTHREAD_H
MyThread.cpp
#include "mythread.h"
#include <QDebug>
#include <QThread>
MyThread::MyThread(QObject *parent) : QObject(parent){
}
void MyThread::MyThreadWork()
{
for(int val=0;val<=100;val++)
{
//向外部发送信号
emit SendVal(val);
//睡眠一秒
QThread::sleep(1);
qDebug()<<val;
}
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QThread>
#include "mythread.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
signals:
void checkMyThread();
private slots:
void RecvVal(int Val);
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QThread m_thread;
MyThread m_ProgressBarVal;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->progressBar->setMaximum(100); //设置进度条最大值
ui->progressBar->setValue(0); //设置进度条当前值为0
ui->statusBar->addWidget(ui->progressBar); //将进度条添加进状态栏MainToolBal
m_ProgressBarVal.moveToThread(&m_thread); //m_ProgressBarVal移动到线程中去
m_thread.start();//开启线程
//关联信号,当触发checkMyThread()信号时执行MyThreadWork()函数
connect(this,SIGNAL(checkMyThread()),&m_ProgressBarVal,SLOT(MyThreadWork()));
//关联信号,当触发SendVal()信号时执行RecvVal()函数,并将值传递过去
connect(&m_ProgressBarVal,SIGNAL(SendVal(int)),this,SLOT(RecvVal(int)));
}
MainWindow::~MainWindow()
{
//线程退出并等待10s
m_thread.exit();
m_thread.wait(1000*10);
delete ui;
}
void MainWindow::RecvVal(int Val)
{
//设置进度条的值
ui->progressBar->setValue(Val);
}
void MainWindow::on_pushButton_clicked()
{
//触发checkMyThread()信号,使MyThreadWork()工作
emit checkMyThread();
}
End
作者 | 梦凡
- 会优化,你真的会优化吗?其实你可能真的缺少一份理解【数据库篇】
- 用户登录安全框架shiro—用户的认证和授权(一)
- 第一道防线__SpringMVC配置拦截器
- Web层框架对网站中所有异常的统一处理
- Spring MVC__自定义日期类型转换器
- 解决在控制层springmvc框架发出的400状态的错误
- 解决springmvc在单纯返回一个字符串对象时所出现的乱码情况(极速版)
- MySQL日志文件之错误日志和慢查询日志详解
- 采用HTML5之"data-"机制自由提供数据
- Spring和SpringMVC父子的容器之道---[上篇]
- 快速完成(图片旋转,查看原图)
- Jsp中格式化时间戳的常用标签
- 反射+自定义注解---实现Excel数据列属性和JavaBean属性的自动映射
- 后台模板管理系统___左侧菜单数据的异步加载
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android7.0以上Uri转路径的方法实现(已验证)
- Android studio实现简单计算器
- Android 自定义LayoutManager实现花式表格
- android studio编译jar包或者aar包的方法教程详解
- Android实现屏幕录制功能
- Android实现扫描二维码功能
- android实现录屏功能
- android自定义手表效果
- Android 测量文字宽度的实例方法
- Android 添加系统服务的方法详解
- android实现录屏小功能
- Android控件CardView实现卡片效果
- 非常好看的android音量旋钮
- Android实现按钮拖拽还原功能
- 百度地图实现小车规划路线后平滑移动功能