QT高级编程技巧(二)-- 编写多线程和并发应用

学习QT多线程编程之前,有必要先熟悉事件循环的概念。先看一个单线程界面程序的主函数代码:

int main(int argc, char* argv[])
{
  QApplication app(argc,  argv);

  // 构造主窗口对象并显示
  MainWindow w;
  w.show();

  // 进入事件循环
  return app.exec();
}

在程序初始化完成后,主线程进入main()函数开始执行应用代码。一般地,我们在主线程上构建界面对象,然后进入事件循环以处理控件绘制、用户输入、系统输出等消息。这就是我们通常说的事件驱动模型。

主线程承担着用户交互的重任,当在主线程上运行费时的代码时,就会影响用户的正常操作。所以我们常把一些费时费力的计算工作移出主线程,开辟新的线程来运行之。

QThread是QT中用于线程管理的类,调用一个QThread对象的start()方法时,会创建一个新的线程并执行它的run()方法。默认地,run()会调用exec()方法进入自己的消息循环中。如下图所示:

上图中有主线程、工作线程都是执行事件循环,并且注意到主线程内部含有thr、w、objs这些QObject对象(这些对象都是在主线程上创建的)。主线程的事件循环负责检测这些对象是否有消息要处理,有的话则调用对象的slot方法。可以使用QObject::moveToThread方法将某个对象移到其他线程中,譬如:

class Worker : public QObject {
    Q_OBJECT
    …
}

void someFunc()
{
   QThread thr = new QThread;
   Worker worker = new Worker;
   worker->moveToThread(thr);
   thr->start();  …
}

如果在主线程上调用someFunc(),则workerThread和worker在创建后都是关联在主线程上,当调用worker->moveToThread()后,worker对象关联到了新的线程中,如图所示:

假定我们在MainWindow上声明了一个worksSignal()消息,在Worker对象上声明和定义了handleWorks()的槽,将worksSignal和handleWorks连接起来的方式有:

1. Qt::AutoConnection - (默认)如果消息对象和槽对象关联在同一线程下,则使用Qt::DirectConnection方式;否则的话,像MainWindow和Worker两个关联在不同线程的对象,将采用Qt::QueuedConnection的方式。

2. QT::DirectConnection - 发送消息的时候将直接调用槽对象的槽方法。注意这里的槽方法是在发送消息的线程上执行的,如果该槽方法是非线程安全的话会有问题的。

3. Qt::QueuedConnection - 发送线程在发送消息后将继续执行,槽对象关联的线程在事件循环时会检测到该消息,并调用相应的槽方法。

4. Qt::BlockingQueuedConnection - 在主线程发送worksSignal消息后,将阻塞直到在工作线程检测到该消息并运行worker->handleWorks()后恢复。

5. Qt::UniqueConnection - 可以和上面4个方式联并(或操作),提示该连接是独一的。提示不能有相同的连接(消息对象和槽对象,消息和槽都相同)出现。

这里特别提醒读者,一般地我们不建议将QThread对象moveToThread到它运行的线程上。原因是QThread是设计成一个管理线程的类,我们不应该在工作线程上管理工作线程,对吧。关于更多的技术细节,我不想多讲了,因为本系列的博文旨在共享经验技巧,而非翻译一些文档。

在项目中,我都是通过继承QThread类实现后台进程的,通过重写run()函数填入线程需要运行的任务。上一篇博文中,我通过在QThread子类上嵌入InThreadObject对象快速实现线程通信的功能,请回顾QT高级编程技巧(一)-- 编写高效的signal & slot通信代码。还有下面一个技巧实现工作线程上的timer事件处理:

void WorkerThread::run()
{
  QTimer tmr;      // 关联在本线程上的QObject对象
  connect(&tmr, &QTimer::timeout, [=](){
    doSomething();
  });
  tmr.start(500);  // 500毫秒计时
  exec();          // 进入事件循环
}

关于多线线程的编程谈论到此,望能起抛砖引玉的效果。在实际的项目,可以参考下面的文档设计多线程或并发的应用:

* QtConcurrent: http://doc.qt.io/qt-5/qtconcurrent.html

* Thread Support in Qt: http://doc.qt.io/qt-5/threads.html

本文链接:http://www.cnblogs.com/wenris/p/4450643.html

作者:wenris,联系:<[email protected]>

后会有期哦 O(∩_∩)O

时间: 2024-08-06 08:31:33

QT高级编程技巧(二)-- 编写多线程和并发应用的相关文章

QT高级编程技巧(一)-- 编写高效的signal &amp; slot通信代码

关于QT的线程通信,我们都会想到signal & slot机制.先回顾下利用signal & slot机制实现控件消息处理的方法. 控件消息处理 假设我们的主界面上有一个使用ui->btn指向的QPushButton对象,要实现该对象的clicked消息处理,可以在主界面对象MainWindow上添加一个slot方法onBtnClicked,并在其构造函数中使用connect方法与ui->btn的clicked消息进行绑定,如下: MainWindow::MainWindow(

Python高级编程技巧实战 基于Python项目与面试题讲解

精选50个Python各领域开发及面试常见问题作为训练任务,每个任务先提出问题,然后分析问题.并给出高效的解决办法,最后手把手带你解决问题,全面提升用Python快速解决问题与高效编程的能力. ----------------------课程目录------------------------------讲师:程序员硕 Linux系统工程师Freescale半导体公司Linux Kernel工程师, 对开源Linux Kernel的mtd模块贡献过多个patch. 在清华大学信研院工作期间, 参

C++Builder 高级编程技巧

1. C++ Builder 网上资源 C++ Builder 研究 http://www.ccrun.com/ C++ Builder 程序员 http://mybcb.diy.myrice.com/ 电脑学习 C++ Builder 版块 http://www.itcomputer.com.cn/Programs/C/CB/ c++ Builder 快捷键大全: http://www.itcomputer.com.cn/Programs/C/CB/200512/11211.html C++

python高级编程技巧

http://blog.sina.com.cn/s/blog_a89e19440101fb28.html Python列表解析语法[]和生成 器()语法类似 [expr for iter_var in iterable] 或 [expr for iter_var in iterable if cond_expr] 例子:[i for i in range(10)if i %2==0] Enumerate >>> i=0 >>> s=['a','b','c'] >&

Python高级编程技巧(转)

译文:http://blog.jobbole.com/61171/ 本文展示一些高级的Python设计结构和它们的使用方法.在日常工作中,你可以根据需要选择合适的数据结构,例如对快速查找性的要求.对数据一致 性的要求或是对索引的要求等,同时也可以将各种数据结构合适地结合在一起,从而生成具有逻辑性并易于理解的数据模型.Python的数据结构从句法 上来看 非常直观,并且提供了大量的可选操作.这篇指南尝试将大部分常用的数据结构知识放到一起,并且提供对其最佳用法的探讨. 推导式(Comprehensi

python 的一些高级编程技巧

正文: 本文展示一些高级的Python设计结构和它们的使用方法.在日常工作中,你可以根据需要选择合适的数据结构,例如对快速查找性的要求.对数据一致性的要求或是对索引的要求等,同时也可以将各种数据结构合适地结合在一起,从而生成具有逻辑性并易于理解的数据模型.Python的数据结构从句法上来看非常直观,并且提供了大量的可选操作.这篇指南尝试将大部分常用的数据结构知识放到一起,并且提供对其最佳用法的探讨. 推导式(Comprehensions) 如果你已经使用了很长时间的Python,那么你至少应该听

Linux Shell 高级编程技巧4----几个常用的shell脚本例子

4.几个常用的shell脚本例子    4.0.在写脚本(同样适用在编程的时候),最好写好完善的注释    4.1.kill_processes.sh(一个杀死进程的脚本) #!/bin/bash current_PID=$$ ps -aux | grep "/usr/sbin/httpd" | grep -v "grep" | awk '{print $2}' > /tmp/${current_PID}.txt for pid in `cat /tmp/${

Linux Shell 高级编程技巧3----运行级别脚本介绍

3.运行级别脚本介绍    3.1.运行级别        运行级别介绍:            0    关机            1    单用户模式            2    多用户模式,没有NFS服务            3    多用户模式            4    目前还没有使用            5    X windows 的启动模式            6    重启计算机        运行级别对应的目录(/etc/rcN.d,N是数字0.1.2...)

python2.7高级编程 笔记二(Python中的描述符)

Python中包含了许多内建的语言特性,它们使得代码简洁且易于理解.这些特性包括列表/集合/字典推导式,属性(property).以及装饰器(decorator).对于大部分特性来说,这些"中级"的语言特性有着完善的文档,并且易于学习. 但是这里有个例外,那就是描述符.至少对于我来说,描述符是Python语言核心中困扰我时间最长的一个特性.这里有几点原因如下: 有关描述符的官方文档相当难懂,而且没有包含优秀的示例告诉你为什么需要编写描述符(我得为Raymond Hettinger辩护一