Qt多线程的实现方式

news2025/1/5 17:48:29

Qt多线程的实现方式

文章目录

  • Qt多线程的实现方式
    • QThread的run方法
    • QObject的moveToThread
    • QRunnalble的run
    • QtConcurrent的run
    • 线程同步
      • 基于QMutex互斥同步
      • 基于QReadWriteLock的线程同步
      • 基于QWaitCondition的线程同步

QThread的run方法

一个QThread对象管理一个线程,一般从QThread继承一个自定义的类,并实现run方法,在run函数中实现线程需要完成的任务。QThread自身定义了started() 和finish()两个信号,started() 信号是在开始执行之前发射,finished()信号是在线程就要结束时发射。

  class WorkerThread : public QThread
  {
      Q_OBJECT
      void run() override {
          // TODO
          emit sigMsg(result);
      }
  signals:
      void sigMsg(const QString &s);
  };

  void main()
  {
      WorkerThread *workerThread = new WorkerThread(this);
      workerThread->start();
  }

特点

1、优点:可以通过信号槽与外界进行通信。
2、缺点:每次新建一个线程都需要继承QThread,实现一个新类,使用不太方便。
要自己进行资源管理,线程释放和删除。并且频繁的创建和释放会带来比较大的内存开销。
3、适用场景:QThread适用于那些常驻内存的任务。

QObject的moveToThread

创建一个继承QObject的类MyThread,把要执行的计算放到一个函数中doWork,然后new一个Qthread,并把创建的myThread类movetothread到创建好的子线程中,然后start子线程,这样就实现了一个子线程。这里一定要通过信号去调用doWork函数。

class MyThread:public QObject
{
    Q_OBJECT
public slots:
    void doWork(){
        int i=0;
        while(i<4){
            // ToDo
            qDebug()<<QThread::currentThread()<<" "<<i++;
        }
    }
​
​
};class MyTest :public QObject
{
    Q_OBJECT
    QThread workerThread;
public:
    MyTest(){
        MyThread* myThread = new MyThread();   // 这个任务函数不能有父对象,有父对象时不可以moveToThread
        myThread->moveToThread(&workerThread);
        workerThread.start();
        connect(this,&MyTest::active,myThread,&MyThread::doWork);  // 一定要通过槽函数去调用对应的函数,否则还是在主线程
    }
    ~MyTest(){
        workerThread.quit();
    }
signals:
    void active();
};MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    qDebug()<<QThread::currentThread();
    ui->setupUi(this);
    MyTest* t = new MyTest();
    t->active();
    QThread::sleep(3000);
    t->deleteLater();
}

特点

一定要通过槽函数的形式去调用函数,要注意!你创建的QThread对象实例,仍然存活在主线程上,而非子线程。所以如果你直接调用其中的函数,那么还是在主线程上运行的。该方法并不是线程安全的。

QRunnalble的run

继承Qrunnable,并重写run虚函数,使用QThreadPool启动线程

class Runnable:public QRunnable
{
public:
       Runnable();
       ~Runnable();
       void run();
};

Runnable::Runnable():QRunnable()
{

}

Runnable::~Runnable()
{
       cout<<"~Runnable()"<<endl;
}

void Runnable::run()
{
       cout<<"Runnable::run()thread :"<<QThread::currentThreadId()<<endl;
       cout<<"dosomething ...."<<endl;
}
int main(int argc, char *argv[])
{
       QCoreApplication a(argc, argv);
       cout<<"mainthread :"<<QThread::currentThreadId()<<endl;
       Runnable runObj;
       QThreadPool::globalInstance()->start(&runObj);
       returna.exec();
}

特点

1,无需手动释放资源,QThreadPool启动线程执行完成后会自动释放。

2,不能使用信号槽与外界通信。

3,QRunnable适用于线程任务量比较大,需要频繁创建线程。QRunnable能有效减少内存开销。

QtConcurrent的run

使用QtConcurrent编写的程序会根据可用的处理器内核数自动调整使用的线程数。QtConcurrent::run能够方便快捷的将任务丢到子线程中去执行,无需继承任何类,也不需要重写函数,使用非常简单。通过QtConcurrent::run()返回的QFuture不支持取消、暂停,返回的QFuture只能用于查询函数的运行/完成状态和返回值。

函数原型:
QFuture<T> QtConcurrent::run(Function function, ...)
QFuture<T> QtConcurrent::run(QThreadPool *pool, Function function, ...)

使用方式
    QtConcurrent::run([=]() {
        // TODO
    });

线程同步

基于QMutex互斥同步

QMutex的目的是保护一个对象、数据结构或者代码段,所以同一时间只有一个线程可以访问它。如果使用Mutex锁那么多个线程在访问一段代码的时候是存在阻塞的,一个执行完毕下一个线程才会继续执行

  • lock():试图锁定互斥量。如果另一个线程已经锁定这个互斥量,那么这次调用将阻塞直到那个线程把它解锁。
  • unlock():进行解锁
  • tryLock():试图锁定互斥量。如果锁被得到,这个函数返回真。如果另一个进程已经锁定了这个互斥量,这个函数返回假,而不是一直等到这个锁可用为止
QMutex mutex;
 void DebugInfo()
 {
    mutex.lock();
    qDebug("ABC");
    qDebug("DEF");
    mutex.unlock();
 }

基于QReadWriteLock的线程同步

一种读写锁,用于保护可以进行读写访问的资源。这种索允许多个线程同时进行只读访问,但是一旦一个线程想要写入资源,则必须阻止所有其他线程,直到写入完成。

 QReadWriteLock lock;

 void ReaderThread::run()
 {
     ...
     lock.lockForRead();
     read_file();
     lock.unlock();
     ...
 }

 void WriterThread::run()
 {
     ...
     lock.lockForWrite();
     write_file();
     lock.unlock();
     ...
 }

void lockForRead():锁定读取锁。如果另一个线程已锁定以进行写入,则此函数将阻塞当前线程。如果线程已经锁定写入,则无法锁定读取。void lockForWrite():锁定写入锁。如果另一个线程(包括当前线程)已锁定读取或写入,则此函数将阻塞当前线程。如果线程已经为读取而锁定,则不会为写入而锁定。

基于QWaitCondition的线程同步

QWaitCondition 允许线程在某些情况发生时唤醒另外的线程。一个或多个线程可以阻塞等待一QWaitCondition ,用wakeOne()或wakeAll()设置一个条件。wakeOne()随机唤醒一个,wakeAll()唤醒所有

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:
     void run();
};
void Producer::run()
{
     qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
     for (int i = 0; i < DataSize; ++i) {
         mutex.lock();
         if (numUsedBytes == BufferSize)
             bufferNotFull.wait(&mutex);
         mutex.unlock();
         buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4];
         mutex.lock();
         ++numUsedBytes;
         bufferNotEmpty.wakeAll();
         mutex.unlock();
     }
}
class Consumer : public QThread
{
public:
     void run();
};
void Consumer::run()
{
     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");
}
int main(int argc, char *argv[])
{
     QCoreApplication app(argc, argv);
     Producer producer;
     Consumer consumer;
     producer.start();
     consumer.start();
     producer.wait();
     consumer.wait();
     return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2270392.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SSM-Spring-AOP

目录 1 AOP实现步骤&#xff08;以前打印当前系统的时间为例&#xff09; 2 AOP工作流程 3 AOP核心概念 4 AOP配置管理 4-1 AOP切入点表达式 4-1-1 语法格式 4-1-2 通配符 4-2 AOP通知类型 五种通知类型 AOP通知获取数据 获取参数 获取返回值 获取异常 总结 5 …

【Linux】:线程安全 + 死锁问题

&#x1f4c3;个人主页&#xff1a;island1314 &#x1f525;个人专栏&#xff1a;Linux—登神长阶 ⛺️ 欢迎关注&#xff1a;&#x1f44d;点赞 &#x1f442;&#x1f3fd;留言 &#x1f60d;收藏 &#x1f49e; &#x1f49e; &#x1f49e; 1. 线程安全和重入问题&…

数字电路期末复习

*前言&#xff1a;*写的东西不太全面&#xff0c;更多的是一个复习大纲&#xff0c;让你发现自己有哪些不懂的问题&#xff08;不懂的地方就去翻书或者问AI&#xff09;&#xff0c;如果能够解决提出的所有问题&#xff0c;那么过期末考一定不是问题。 这里写目录标题 数制和码…

python数据分析:使用pandas库读取和编辑Excel表

使用 Pandas&#xff0c;我们可以轻松地读取和写入Excel 文件&#xff0c;之前文章我们介绍了其他多种方法。 使用前确保已经安装pandas和 openpyxl库&#xff08;默认使用该库处理Excel文件&#xff09;。没有安装的可以使用pip命令安装&#xff1a; pip install pandas ope…

“AI人工智能软件开发公司:创新技术,引领未来

大家好&#xff01;今天我们来聊聊一个充满未来感的话题——AI人工智能软件开发公司。这个公司&#xff0c;用大白话说&#xff0c;就是专门研究和开发人工智能软件的地方&#xff0c;它们用最新的技术帮我们解决问题&#xff0c;让生活和工作变得更智能、更便捷。听起来是不是…

uniapp中使用ruoyiPlus中的加密使用(crypto-js)

package.json中添加 "crypto-js": "^4.2.0", "jsencrypt": "^3.3.2",但是vue2中使用 import CryptoJS from cryptojs; 这一步就会报错 参照 参照这里&#xff1a;vue2使用CryptoJS实现信息加解密 根目录下的js文档中新增一个AESwork.…

【SQL Server】教材数据库(1)

1 利用sql建立教材数据库&#xff0c;并定义以下基本表&#xff1a; 学生&#xff08;学号&#xff0c;年龄&#xff0c;性别&#xff0c;系名&#xff09; 教材&#xff08;编号&#xff0c;书名&#xff0c;出版社编号&#xff0c;价格&#xff09; 订购&#xff08;学号…

全国计算机设计大赛大数据主题赛(和鲸赛道)经验分享

全国计算机设计大赛大数据主题赛&#xff08;和鲸赛道&#xff09;经验分享 这是“和鲸杯”辽宁省普通高等学校本科大学生计算机设计竞赛启动会汇报—大数据主题赛的文档总结。想要参加2025年此比赛的可以借鉴。 一、关于我 人工智能专业 计赛相关奖项&#xff1a; 2022年计…

AI对接之JSON Output

AI的JSON Output 实际对接指南 前言 本系列AI的API对接均以 DeepSeek 为例&#xff0c;其他大模型的对接方式类似。 在现代软件开发中&#xff0c;JSON&#xff08;JavaScript Object Notation&#xff09;作为一种轻量级的数据交换格式&#xff0c;因其简洁和易于人阅读的特…

Vue3实现PDF在线预览功能

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Vue篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Vue篇专栏内容:Vue3现PDF在线预览功能 前言 在开发中&#xff0c;PDF预览和交互功能是一个常见的需求。无论是管理…

SpringBootWeb案例-1

文章目录 SpringBootWeb案例1. 准备工作1.1 需求&环境搭建1.1.1 需求说明1.1.2 环境搭建 1.2 开发规范 2. 部门管理2.1 查询部门2.1.1 原型和需求2.1.2 接口文档2.1.3 思路分析2.1.4 功能开发2.1.5 功能测试 2.2 前后端联调2.3 删除部门2.3.1 需求2.3.2 接口文档2.3.3 思路…

css实现垂直文本

效果 知识 writing-mode: <value>; 可选值 horizontal-tb: 默认值。文本从左到右&#xff08;或从右到左&#xff09;排列&#xff0c;然后从上到下。vertical-rl: 文本从上到下排列&#xff0c;然后从右到左。适用于垂直书写的方向&#xff0c;如日语和中文。vertica…

vim里搜索关键字

vim是linux文本编辑器的命令&#xff0c;再vi的基础上做了功能增强 使用方法如下 1. / 关键字, 回车即可, 按n键查找关键字下一个位置 2.? 关键字, 回车即可, 按n键查找关键字下一个位置 3.示例

Qt之QtConcurrent

简介 QtConcurrent是针对qt中多线程相关的高层封装&#xff0c;如QFuture 结构 Qtconcurrent命名空间中的run支持的有 其对应的functor下结构为 类关系 functor对应的类核心关系为 #mermaid-svg-KLxZquz9yRsiYvQL {font-family:"trebuchet ms",verdana,a…

鸿蒙应用开发搬砖经验之-ArkWeb加载页面的超简单示例

前言 系统环境&#xff1a;Mac mini M2 14.5 (23F79) 开发IDE&#xff1a;DevEco Studio 5.0.1 Release 示例 第一步&#xff1a;创建一个Empty Ability工程 第二步&#xff1a;先run一下&#xff0c;确定工程初步化正常&#xff0c;模拟器正常启动应用&#xff08;要先提…

大模型系列17-RAGFlow搭建本地知识库

大模型系列17-RAGFlow搭建本地知识库 安装ollama安装open-wehui安装并运行ragflowRAG&#xff08;检索、增强、生成&#xff09;RAG是什么RAG三过程RAG问答系统构建步骤向量库构建检索模块生成模块 RAG解决LLM的痛点 使用ragflow访问ragflow配置ollama模型添加Embedding模型添加…

SimForge HSF 案例分享|复杂仿真应用定制——UAVSim无人机仿真APP(技术篇)

导读 「神工坊」核心技术——「SimForge HSF高性能数值模拟引擎」支持工程计算应用的快速开发、自动并行&#xff0c;以及多域耦合、AI求解加速&#xff0c;目前已实现航发整机数值模拟等多个系统级高保真数值模拟应用落地&#xff0c;支持10亿阶、100w核心量级的高效求解。其低…

微电网到底是什么?和光伏有什么关系?

在现代能源体系中&#xff0c;微电网作为一种新型的电力系统结构&#xff0c;正逐渐受到广泛关注和应用。那么&#xff0c;微电网到底是什么&#xff1f;它与光伏又有怎样的关系呢&#xff1f;本文将对此进行详细解析。 微电网的基本概念 微电网&#xff08;Micro-Grid&#x…

印象笔记06——再谈谈更新

印象笔记06——再谈谈更新 [!CAUTION] 好吧&#xff0c;我承认在前五期的努力下&#xff0c;我还是用的obsidian多一些。印象笔记很大程度用来弄清单&#xff0c;但是扭头看了看自己的会员时间&#xff0c;不能浪费啊&#xff01;本期再谈谈印象笔记近期的一些更新&#xff0c;…

爱死机第四季(秘密关卡)4KHDR国语字幕

通过网盘分享的文件&#xff1a;love_death_robot 链接: https://pan.baidu.com/s/1bG3Xtdopenil2O_y93hY_g?pwd8kib 提取码: 8kib