第十三章:QT多线程(QThread)

2023-11-06

回顾:
第一章:Qt的概述
第二章:在Ubuntu编写第一个Qt程序
第三章:Qt的字符串和字符编码
第四章:Qt的信号和槽
第五章:Qt容器窗口(父窗口)
第六章:面向对象的Qt编程
第七章:Qt设计师使用(designer)
第八章:Qt创造器的使用(qtcreator)
第九章:资源和图像
第十章:目录与定时器
第十一章:鼠标和键盘事件
第十二章:Qt数据库(sqlite)

QT多线程(QThread)

1、创建线程方式//pthread_create
  • 1)方法1:QObject::moveToRhread()
  class Worker : public QObject
  {
      Q_OBJECT

  public slots:
      void doWork(const QString &parameter) {
          QString result;
          /* ... here is the expensive or blocking operation ... */
          /* 耗时或阻塞的操作需要放在独立线程去执行 */
          emit resultReady(result);
      }

  signals:
      void resultReady(const QString &result);
  };

  class Controller : public QObject
  {
      Q_OBJECT
      QThread workerThread;
  public:
      Controller() {
      //创建worker对象,它里面的dowork需要放到线程中
          Worker *worker = new Worker;
          将worker移动到workerThread线程对象中
          worker->moveToThread(&workerThread);
          //当operate发送时,dowork将会在独立线程中被执行
          connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
          connect(this, &Controller::operate, worker, &Worker::doWork);
          connect(worker, &Worker::resultReady, this, &Controller::handleResults);
          //开启线程
          workerThread.start();
      }
      ~Controller() {
          workerThread.quit();
          workerThread.wait();
      }
  public slots:
      void handleResults(const QString &);
  signals:
      void operate(const QString &);
  };

  • 2)方法2:继承QThread,重写run函数
  class WorkerThread : public QThread
  {
      Q_OBJECT
      void run() override {
          QString result;
          /* ... here is the expensive or blocking operation ... */
           /* 耗时或阻塞的操作需要放在独立线程去执行 */
          emit resultReady(result);
      }
  signals:
      void resultReady(const QString &s);
  };

  void MyObject::startWorkInAThread()
  {
  	  //创建线程对象那个
      WorkerThread *workerThread = new WorkerThread(this);
      connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
      connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
      //开启线程,子类中重写run函数将在独立线程中被执行
      workerThread->start();
  }
2、线程操作相关函数
  • 1)开启线程pthread_create
void start();
  • 2)退出线程
void exit();
void quit()[slot];
  • 3)等待线程pthread_join
void wait();
  • 4)终止线程pthread_cancel
void terminate();

注意使用了terminate函数后,一般要调用wait函数,等待系统回收资源,否则容易导致资源浪费或者内存泄漏

eg1:
void run(void){
	new 内存;
	...
	被终止:terminate;
	...
	delete 内存;
	...
}

eg2:
void run(void){
	...
	加锁;
	...
	访问全局资源;
	...
	被终止:terminate;
	...
	解锁;
	...
}
  • 5)设置线程是否允许被取消setTerminationEnabled
//enabled=true:默认可以被终止,false默认不允许被终止
void QThread::setTerminationEnabled(bool enabled)
eg:
void run(void){
	...
	...
	setTerminationEnabled(false);
	正在执行关键操作:动态资源、数据库、加锁解锁...
	setTerminationEnabled(true);
	...
	...
}
  • 6)获取当前线程的句柄(ID)
Qt::HANDLE currentThreadId()

案例:多线程打印消息

  • 主线程:ThreadDialog.h, ThreadDialog.cpp
  • 子线程:WorkThread.h, WorkThread.cpp

ThreadDialog.h

#ifndef THREADDIALOG_H
#define THREADDIALOG_H

#include <QDialog>
#include "WorkThead.h"

QT_BEGIN_NAMESPACE
namespace Ui { class ThreadDialog; }
QT_END_NAMESPACE

class ThreadDialog : public QDialog
{
    Q_OBJECT

public:
    ThreadDialog(QWidget *parent = nullptr);
    ~ThreadDialog();

private slots:
    void on_startButton_clicked();

    void on_stopButton_clicked();

private:
    Ui::ThreadDialog *ui;

    WorkThead threadA;
    WorkThead threadB;
};
#endif // THREADDIALOG_H

ThreadDialog.cpp

#include "ThreadDialog.h"
#include "ui_ThreadDialog.h"

ThreadDialog::ThreadDialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::ThreadDialog)
{
    ui->setupUi(this);
}

ThreadDialog::~ThreadDialog()
{
    delete ui;
}


void ThreadDialog::on_startButton_clicked()
{
    //
    threadA.start();
    threadB.start();
    ui->startButton->setEnabled(false);
    ui->stopButton->setEnabled(true);
}



void ThreadDialog::on_stopButton_clicked()
{
    threadA.terminate();
    threadA.wait();//
    threadB.terminate();
    threadB.wait();
    ui->startButton->setEnabled(true);
    ui->stopButton->setEnabled(false);
}

WorkThread.h

#ifndef WORKTHEAD_H
#define WORKTHEAD_H

#include <QThread>
#include <QDebug>

//1)继承QThread
class WorkThead:public QThread
{
public:
    WorkThead();
    ~WorkThead();
protected:
    //2)重写run函数
    void run(void);
};

#endif // WORKTHEAD_H

WorkThread.cpp

#include "WorkThead.h"

WorkThead::WorkThead()
{

}

WorkThead::~WorkThead()
{

}

void WorkThead::run(void)
{
    unsigned long threadId = (unsigned long)currentThreadId();
    while(1){
        qDebug("id=%lu", threadId);
        msleep(500);
    }
}

在这里插入图片描述

3、线程同步
  • 1)QMutex 互斥锁(互斥量)
    eg:
QMutex mutex;
void run(void){//线程1
	mutex.lock();
	访问共享资源;
	mutex.unlock();
}
void run(void){//线程2
	mutex.lock();
	访问共享资源;
	mutex.unlock();
}
  • 2)QReadWriteLock 读写锁
    eg:
QReadWriteLock lock;
void ReaderThread::run(){
	...
	lock.lockForRead();
	read_file();
	lock.unlock();
}
void WriterThread::run(){
	...
	lock.lockForWrite();
	write_file();
	lock.unlock();
}
  • 3)QSemaphore 信号量
    在这里插入图片描述
// 初始化信号计数5:表示有5个可用的共享资源
QSemaphore sem(5);      // sem.available() == 5
//获取3个共享资源,剩余2个可用的
sem.acquire(3);         // sem.available() == 2
//获取2个共享资源,剩余0个可用的
sem.acquire(2);         // sem.available() == 0
//释放5个共享资源,剩余5可用的
sem.release(5);         // sem.available() == 5
//又分配5个共享资源,剩余10可用的
sem.release(5);         // sem.available() == 10

//尝试获取1个,成功返回true
sem.tryAcquire(1);      // sem.available() == 9, returns true
//尝试获取250个
sem.tryAcquire(250);    // sem.available() == 9, returns false

生产者和消费者:

  #include <QtCore>

  #include <stdio.h>
  #include <stdlib.h>

  const int DataSize = 100000;

  const int BufferSize = 8192;
  char buffer[BufferSize];

  QSemaphore freeBytes(BufferSize);
  QSemaphore usedBytes;

  class Producer : public QThread
  {
  public:
      void run() override
      {
          for (int i = 0; i < DataSize; ++i) {
              freeBytes.acquire();
              buffer[i % BufferSize] = "ACGT"[QRandomGenerator::global()->bounded(4)];
              usedBytes.release();
          }
      }
  };

  class Consumer : public QThread
  {
      Q_OBJECT
  public:
      void run() override
      {
          for (int i = 0; i < DataSize; ++i) {
              usedBytes.acquire();
              fprintf(stderr, "%c", buffer[i % BufferSize]);
              freeBytes.release();
          }
          fprintf(stderr, "\n");
      }
  };

  int main(int argc, char *argv[])
  {
      QCoreApplication app(argc, argv);
      Producer producer;
      Consumer consumer;
      producer.start();
      consumer.start();
      producer.wait();
      consumer.wait();
      return 0;
  }
  • 4)QWaitCondition 条件变量
    生产者和消费者
  const int DataSize = 100000;

  const int BufferSize = 8192;
  char buffer[BufferSize];

  QWaitCondition bufferNotEmpty;
  QWaitCondition bufferNotFull;
  QMutex mutex;
  int numUsedBytes = 0;

  class Producer : public QThread
  {
  public:
      Producer(QObject *parent = NULL) : QThread(parent)
      {
      }

      void run() override
      {
          for (int i = 0; i < DataSize; ++i) {
              mutex.lock();
              if (numUsedBytes == BufferSize)
                  bufferNotFull.wait(&mutex);
              mutex.unlock();

              buffer[i % BufferSize] = "ACGT"[QRandomGenerator::global()->bounded(4)];

              mutex.lock();
              ++numUsedBytes;
              bufferNotEmpty.wakeAll();
              mutex.unlock();
          }
      }
  };

  class Consumer : public QThread
  {
      Q_OBJECT
  public:
      Consumer(QObject *parent = NULL) : QThread(parent)
      {
      }

      void run() override
      {
          for (int i = 0; i < DataSize; ++i) {
              mutex.lock();
              if (numUsedBytes == 0)
                  bufferNotEmpty.wait(&mutex);
              mutex.unlock();

              fprintf(stderr, "%c", buffer[i % BufferSize]);

              mutex.lock();
              --numUsedBytes;
              bufferNotFull.wakeAll();
              mutex.unlock();
          }
          fprintf(stderr, "\n");
      }

  signals:
      void stringConsumed(const QString &text);
  };
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

第十三章:QT多线程(QThread) 的相关文章

随机推荐

  • ESP32 上快捷部署 Tensorflow lite 机器学习(TinyML)

    在这篇文章中 我将向您展示使用 Arduino IDE 将 TensorFlow Lite 模型部署到 ESP32 的最简单方法 无需任何编译内容 Arduino 库 这个 Arduino 库是为了简化使用 Arduino IDE 将用于微
  • 4.8xml于json

    HTTP 协议 HyperText Transfer Protocol 超文本传输协议 是 TCP IP 协议集中的协议 是一个简单的请求 响应协议 指 定了客户端发送给服务器的消息以及服务器的响应 所有的 WWW 文件都必须遵守这个标准
  • matplotlib绘制饼状图

    源自http blog csdn net skyli114 article details 77508430 ticket ST 41707 PzNbUDGt6R5KYl3TkWDg passport csdn net pyplot使用pl
  • 接口测试基础

    目录 一 接口及接口测试概念 1 接口 接口的类型 2 接口测试 二 HTTP协议 1 HTTP协议的特点 2 URL格式 3 HTTP请求 4 HTTP响应 三 接口规范 1 传统风格接口 2 RESTful风格接口 四 接口测试流程 1
  • Python 11. OpenCV 透视变换

    import cv2 import numpy as np from matplotlib import pyplot as plt img cv2 imread pic4 PNG rows cols img shape 2 cv2 ims
  • 支持图文转换!PSD文档处理工具Aspose全新升级

    Aspose PSD是高级PSD和入门级AI文件格式操作API 允许创建和编辑Photoshop文件 并提供更新图层属性 添加水印 执行图形操作或将一种文件格式转换为另一种文件的功能 没有任何Adobe Photoshop或Adobe Il
  • [系统

    系统环境说明 系统 Deepin V20 平台 amd64 参考文献 asdf maven asdf document asdf plugins asdf vm安装 见多版本管理命令行工具asdf vm安装及使用 asdf vm安装Mave
  • 「C++学习笔记」面向.Net Core的(C++)CLR类库非专业入门(+使用Opencv)

    关键词 C CLR Net Core Net Famework Opencv C 目录 什么是CLR类库 本文说明 创建Demo程序 调用dll 通过项目引用 通过dll文件引用 其他还没完全清楚的坑 有关C CLI这块的资料真的很少而且都
  • 如何看待ChatGPT

    如何看待ChatGPT 如何看待ChatGPT 语言学家乔姆斯基说 这是一个抄袭的机器 欺骗性机器 ChatGPT使用大量文本数据进行训练 然后以一种令人信服的修饰语句展现 这使得它和人的互动能力更加契合 但是仍然不是一个充满创造力的智能机
  • 微信小程序之拨打电话

    微信小程序拨打电话功能的实现是采用wx makePhoneCall 具体方法如下 wxml lt view gt 电话 15888888888 lt view data ph 15888888888 bindtap callPhone gt
  • 【Android 12 AOSP学习】Android 12源码下载编译

    一 搭建环境 liunx系统 Ubuntu20 04 Android系统 12 1 安装 Repo 下载Repo前先安装 curl 库 sudo apt get install curl 下载好 curl 库后 设置清华源下载 Repo 然
  • 前端 JavaScript 提取 JSON 数据

    原文地址 假如我们从后端接收到了以下 JSON 数据 id 1 name Xu Albter age 18 使用 JSON parse 方法处理以上数据 将其转换为 JavaScript 对象 var obj JSON parse id 1
  • select函数缺陷分析

    与poll和epoll不同 select函数是事件为单位组织文件描述符 监视的行为较为单一 函数原型 int select int nfds fd set readfds fd set writefds fd set exceptfds s
  • 链表应用:两数相加

    关于链表 链表是一种极其重要的数据结构 因为对指针和抽象思维的要求较高 一度成为身边同学最痛恨的对象 我在将这里演示如何使用链表制作一个可以按位储存数字的容器 鉴于本人亦初学者 有错误请各位在评论区指正 这里还是以介绍链表为主 算法部分苦于
  • SpringCloud和微服务介绍

    SpringCloud介绍 微服务架构是什么 微服务实例的开发 服务的注册与发现 负载均衡 服务容错 API网关 分布式配置中心 调试 部署 持续集成 SpringCloud介绍 SpringCloud是在SpringBoot的基础上构建的
  • 一个完整详细的二维SVR案例分析过程

    文章目录 案例介绍 数据预处理 函数拟合仿真 SVR建模 模型调参 案例介绍 首先 此次案例是以油气开发为背景 选取加粗样式其中重要的两个参数含油饱和度和孔隙度分别作为此次案例的自变量和因变量进行试验 按照正常的案例分析步骤进行操作 此次为
  • 神经网络(ANN)

    算法介绍 概念 人工神经网络是由具有适应性的简单单元组成的广泛并行互连的网络 它的组织能够模拟生物神经神经系统对真实世界物体所作出的交互反应 在实际应用中 80 90 的人工神经网络模型是采用误差反转算法或其变形形式的网络模型 一个神经网络
  • 小程序的配置文件和小程序的模板语法

    微信小程序 小程序的配置文件 一个小程序应用程序会包括 会有最基本的两种配置文件 一种是全局的 app json 一种是页面自己的 page json 注意 配置文件中不可以出行注释 1 1 全局配置文件 app json app json
  • 主题模型(Topic Model)与LDA算法

    Topic Model 主题模型 Topic Model 是以非监督学习的方式对文档的隐含语义结构 latent semantic structure 进行聚类 clustering 的统计模型 主题模型认为在词 word 与文档 docu
  • 第十三章:QT多线程(QThread)

    回顾 第一章 Qt的概述 第二章 在Ubuntu编写第一个Qt程序 第三章 Qt的字符串和字符编码 第四章 Qt的信号和槽 第五章 Qt容器窗口 父窗口 第六章 面向对象的Qt编程 第七章 Qt设计师使用 designer 第八章 Qt创造