【为什么要用多线程?】

传统的图形用户界面应用程序都只有一个执行线程,并且一次只执行一个操作。如果用户从用户界面中调用一个比较耗时的操作,当该操作正在执行时,用户界面通常会冻结而不再响应。这个问题可以用事件处理和多线程来解决。

【使用多线程有什么好处?】

  1. 提高应用程序的响应速度。这对于开发图形界面程序尤其重要,当一个操作耗时很长时(比如大批量I/O或大量矩阵变换等CPU密集操作),整个系统都会等待这个操作,程序就不能响应键盘、鼠标、菜单等操作,而使用多线程技术可将耗时长的操作置于一个新的线程,从而避免上述问题。

  2. 使多CPU系统更加有效。当线程数不大于CPU数目时,操作系统可以调度不同的线程运行于不同的CPU上。

  3. 改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为独立或半独立的运行部分,这样有利于程序的理解和维护。

【Qt中创建线程的方法】

只需要子类化QThread并重新实现它的run()函数就可以了。run()是个纯虚函数,是线程执行的入口,在run()里出现的代码将会在另外线程中被执行。run()函数是通过start()函数来实现调用的。

【实例】

下面一个例子给出了在应用程序中除了主线程外,还提供了线程A和B。如果单击窗口中的按钮“Start A”,Qt的控制台就会连续输出字母“A”,此时按钮“Start A”被刷新为“Stop A”。再单击按钮“Start B”,控制台会交替输出字母“A”和“B”。如果再单击按钮“Stop A”,则控制台只输出字母“B”。如下图所示:

thread.h代码

#ifndef THREAD_H #define THREAD_H  #include  #include   class Thread : public QThread {     Q_OBJECT public:     Thread();     void setMessage(QString message);     void stop();  protected:     void run();      void printMessage();  private:     QString messageStr;     volatile bool stopped; };  #endif // THREAD_H

注:

  • stopped被声明为易失性变量(volatile variable,断电或中断时数据丢失而不可再恢复的变量类型),这是因为不同的线程都需要访问它,并且我们也希望确保它能在任何需要的时候都保持最新读取的数值。如果省略关键字volatile,则编译器就会对这个变量的访问进行优化,可能导致不正确的结果。

thread.cpp代码

 #include "thread.h" #include   Thread::Thread() {     stopped = false; }  void Thread::run() {     while(!stopped)     {         printMessage();     }     stopped = false; }  void Thread::stop() {     stopped = true; }  void Thread::setMessage(QString message) {     messageStr = message; }  void Thread::printMessage() {     qDebug()<     sleep(1); }

注:

  • QTread提供了一个terminate()函数,该函数可以再一个线程还在运行的时候就终止它的执行,但不推荐用terminate(),因为terminate()不会立刻终止这个线程,该线程何时终止取决于操作系统的调度策略,也就是说,它可以随时停止线程执行而不给这个线程自我清空的机会。更安全的方法是用stopped变量和stop()函数,如例子所示。

  • 调用setMessage()让第一个线程每隔1秒打印字母“A”,而让第二个线程每隔1秒打印字母“B”。

  • 线程会因为调用printf()而持有一个控制I/O的锁,多个线程同时调用printf()在某些情况下回造成控制台输出阻塞,而用qDebug()作为控制台输出一般不会出现上述问题。

threaddialog.h代码

 #ifndef THREADDIALOG_H #define THREADDIALOG_H  #include  #include  #include  #include "thread.h"  class ThreadDialog : public QDialog {     Q_OBJECT  public:     ThreadDialog(QWidget *parent=0);  protected:     void closeEvent(QCloseEvent *event);  private slots:     void startOrStopThreadA();     void startOrStopThreadB();     void close();  private:     Thread threadA;     Thread threadB;     QPushButton *threadAButton;     QPushButton *threadBButton;     QPushButton *quitButton; };  #endif // THREADDIALOG_H

threaddialog.cpp代码

 #include "threaddialog.h"  ThreadDialog::ThreadDialog(QWidget *parent) : QDialog(parent) {     threadA.setMessage("A");     threadB.setMessage("B");      threadAButton = new QPushButton(tr("Start A"), this);     threadAButton->setGeometry(10, 30, 80, 30);     threadBButton = new QPushButton(tr("Start B"),this);     threadBButton->setGeometry(110, 30, 80, 30);     quitButton = new QPushButton(tr("Quit"), this);     quitButton->setGeometry(210, 30, 80, 30);     quitButton->setDefault(true);      connect(threadAButton, SIGNAL(clicked()), this, SLOT(startOrStopThreadA()));     connect(threadBButton, SIGNAL(clicked()), this, SLOT(startOrStopThreadB()));     connect(quitButton, SIGNAL(clicked()), this, SLOT(close())); }  void ThreadDialog::startOrStopThreadA() {     if(threadA.isRunning())     {         threadAButton->setText(tr("Stop A"));         threadA.stop();         threadAButton->setText(tr("Start A"));     }     else     {         threadAButton->setText(tr("Start A"));         threadA.start();         threadAButton->setText(tr("Stop A"));     } }  void ThreadDialog::startOrStopThreadB() {     if(threadB.isRunning())     {         threadBButton->setText(tr("Stop B"));         threadB.stop();         threadBButton->setText(tr("Strat B"));     }     else     {         threadBButton->setText(tr("Start B"));         threadB.start();         threadBButton->setText(tr("Stop B"));     } }  void ThreadDialog::closeEvent(QCloseEvent *event) {     threadA.stop();     threadB.stop();     threadA.wait();     threadB.wait();     event->accept(); }  void ThreadDialog::close() {     exit(0); }

注:

  • startOrStopA的逻辑是:当单击A的按钮时,如果系统判断到有线程A在运行中,就把A的按钮刷新为“Stop A”,表示可以进行stop A的动作,并停止线程A的运行,再将A的按钮刷新为“Start A”。否则,如果线程A没有运行,就把按钮刷新为表示可以运行的“Start A”,启动线程A,然后将A按钮刷新为“Stop A”。

  • 当不用Qt设计器时,new一个button出来,需要指定一个父类,比如this,否则运行程序,窗口里没有按钮。

  • new了多个按钮或控件,需要用setGeometry来确定它们的大小和位置,否则前面的被后面的覆盖,最终看到的是最后一个按钮。setGeometry的前2个参数是相对于窗口的坐标位置,后两个参数是按钮的长宽。

  • 单击Quit或关闭窗口,就停止所有正在运行的线程,并且在调用函数QCloseEvent::accept()之前等待它们完全结束,这样就可以确保应用程序是以一种原始清空的状态退出的。

  • 如果没有62~65行的重新定义close函数,使进程完全退出。否则点击Quit按钮或叉号退出窗口后,进程依然驻留在系统里。

main.cpp代码

 #include "threaddialog.h" #include   int main(int argc, char *argv[]){     QApplication app(argc, argv);     ThreadDialog *threaddialog = new ThreadDialog;     threaddialog->exec();     return app.exec(); }

注:

  • 在GUI程序中,主线程也被称为GUI线程,因为它是唯一一个允许执行GUI相关操作的线程。必须在创建一个QThread之前创建QApplication对象。

运行结果:

项目百度网盘瞎咋链接:

https://pan.baidu.com/s/1N-3NsA41R7Laq9cfSFc9Ew

提取码: 43rb

qt 子窗口写到线程就卡死_Qt多线程创建相关推荐

  1. qt 子窗口写到线程就卡死_QT/C++实现卡通漫画风格化

    先放一些结果图. 除去界面,图像处理部分的原理很简单,主要用到这4个: 1. 上采样和下采样. 2. 双边滤波. 3. 中值滤波. 4. 边缘检测. 大致流程是先多次下采样缩小图片,然后进行多次双边滤 ...

  2. qt 子窗口写到线程就卡死_我的憨憨女友都能看懂学会的Python多线程

    原文:https://urlify.cn/vIneu2 我和我的女朋友因为python而相识,同时也是因为python我才能把憨憨追到手.最近我和我女朋友在做一个项目,我负责语音识别和TTS,她负责Q ...

  3. qt 子窗口写到线程就卡死_微信白屏卡死?

    自去年开始,小宇就经常能够听见身边朋友说微信白屏卡死啦怎么回事呀? 是不是三星手机问题!以前明明好好的呀----- 可能你也曾经遇到过,或者正在煎熬之中.今天就来谈谈我对这个问题的看法. 专业水平有限 ...

  4. qt 子窗口与父窗口数据通信_Qt实例--主窗口和子窗口互发信号

    准备工作: 需要首先添加一个Qt设计师界面类,这里使用默认类名Form. 实例一:主窗口向子窗口发送信号 在主窗口添加一个按钮QPushButton,在子窗口添加一个标签QLabel. 主窗口添加一个 ...

  5. Qt子窗口QMidSubwindow全屏出现的问题总结

    我的需求:想全屏一个子窗口QMidSubwindow,禁止显示最大化最小化和关闭按钮. 我开始尝试的是网上介绍的方法,把结果展现给大家一下,最后再总结: 方法1:QMidSubwindow直接调用sh ...

  6. 子窗口_不同线程下主窗口与子窗口的信息交互(一)

    在使用aardio编程时(aardio官方网站:http://www.aardio.com/),如何实现主界面线程与子窗口线程的信息交互?我们用实例来逐步研究一下. 一.在子线程运行一个子窗体 1.先 ...

  7. qt获取窗口的右上角位置_如何获得 Qt窗口部件在主窗口中的位置--确定鼠标是否在某一控件上与在控件上的位置...

    用Qt Creator 设计程序时,最方便的就是ui设计器,可以很容易的得到想要的布局. 但是这样自动布局带来的后果是很难知道窗口中某一部件在主窗口中的相对位置. 在处理子窗口鼠标事件时变的很麻烦.主 ...

  8. win32开发(创建子窗口)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 在win32中,有的时候需要创建额外的子窗口.所谓子窗口的概念,就是窗口本身不会超出母窗口的边界 ...

  9. mfc 子窗口 跟随 主窗口

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明 http://shujiantang.blogbus.com/logs/29644154.html 前不久做了一个MFC项目.项目做完 ...

最新文章

  1. 转!!java中File的delete()方法删除文件失败的原因
  2. 7.18 collection random os sys等模块
  3. 实例37:python
  4. 数通手稿留档——Frame Relay
  5. Julia : array[ ] 与几种过滤条件
  6. u3d目标与摄像机之间的遮挡物变为透明
  7. 软工网络15团队作业4-DAY2
  8. php把amr转换成mp3,php 微信amr转mp3的方法
  9. 基于神经网络的房价预测,BP神经网络预测房价
  10. PDF文件太大怎么压缩
  11. html中form异步验证,form表单验证
  12. SCI英语论文长难句攻略
  13. 计算机网络与Internet发展历史
  14. [推荐给程序员]热诚和勇气的力量
  15. Flowable 服务任务执行的三种方式
  16. django迁移数据makemigrations不创建APP中的数据表
  17. Electron:WARNING Too many active WebGL contexts. Oldest context will be lost.
  18. 光纤的模式-单模和多模
  19. 经典升级,长直播,马上开课 | 第 20 期高级转录组分析和R数据可视化火热报名中!!!...
  20. dede自动排版 php,站长必备:dedecms正文自动排版、伪原创插件

热门文章

  1. RabbitMQ的五种模型
  2. SQL---- 为树添加一个字段(是否有子节点)
  3. r语言 fourth entry_第四篇 语言学习的自然顺序
  4. 不能使用泛型的形参创建对象_数据类型之----泛型
  5. 腾讯地图api修改信息窗口样式_ThingJS通过地图的信息窗口展示常见数据
  6. Tomcat与JDK版本对应关系
  7. 2018四川高考文科21题
  8. Kubernetes知识体系-从入门到精通
  9. 微信公众平台开发,API接入与推送事件(1)
  10. 离别海润光伏:杨怀进的“轮回怪圈”