【为什么要用多线程?】

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

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

  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 messagebox退出程序_Qt多线程创建相关推荐

  1. qt 子窗口写到线程就卡死_Qt多线程创建

    [为什么要用多线程?] 传统的图形用户界面应用程序都只有一个执行线程,并且一次只执行一个操作.如果用户从用户界面中调用一个比较耗时的操作,当该操作正在执行时,用户界面通常会冻结而不再响应.这个问题可以 ...

  2. qt messagebox退出程序_[Qt] Mac平台安装最新版qt的方法(源码编译) - 刘傲天

    安装方式 安装方式有在线(online)和离线(offline)两个选项,因为在线安装可能要连接国外的服务器非常慢,还会经常失败,所以我们选择离线安装(offline). 选择安装方式 打开https ...

  3. qt messagebox退出程序_删除英雄联盟LOL电视台,QT语音直播,TP安全中心

    大家都知道腾讯游戏都会有各种捆绑安装,与游戏本不相干的程序,还有一些是不断增加的更新文件,这些都要定期清理,能提高游戏运行质量,提高FPS,减少网络延迟.丢包率.这里需要提醒的是,使用wegame平台 ...

  4. QT 多线程创建方法及应用实例

    QT 多线程创建方法及应用实例 方法一: (1)创建一个QT应用 (2)创建线程类,继承QThread simplethreadone.h #ifndef SIMPLETHREADONE_H #def ...

  5. Qt中另一种创建线程的方式

    文章目录 1 Qt中另一种创建线程的方式 1.1 另一种创建线程的方式 1.2 同步型线程的设计 1.3 异步型线程的设计 1 Qt中另一种创建线程的方式 1.1 另一种创建线程的方式 历史的痕迹: ...

  6. Qt的Tcp服务器多线程编程-附带代码展示

    Qt的Tcp服务器多线程编程-附带代码展示 该程序主要实现tcp服务器如何使用多线程的方式来连接多个客户端,此文章没有实现客户端的多线程编程. 创建子线程时需要注意的点: 1.子线程与主线程之间交互数 ...

  7. 在Qt中使用C++代码创建界面

    好儿郎~志在四方 Qt视频教程地址:http://space.bilibili.com/84360636/#!/index 目录视图 摘要视图 订阅 图灵赠书--程序员11月书单    [思考]Pyt ...

  8. 使用QT SDK 1.1 Qt Creator 2.0.9创建symbian sisx安装包

    使用QT SDK 1.1 Qt Creator 2.0.9创建symbian sisx安装包 目前最新(文章记录时刻)的QT SDK 1.1相较于原1.0版本创建symbian sisx安装包非常的不 ...

  9. Android 多线程创建

    Android多线程创建,两种方式 1.继承Thread类 2.实现Runable接口 这两种属于Java多线程的创建,这里不做总结.下面总结一下两种的区别: 继承Thread类,属于继承,存在缺陷, ...

  10. Python3进阶--Socket编程、多线程(创建方式、线程通信、线程锁、线程池)

    第一章 变量.常用循环体.代码结构.代码练习 第二章 列表.元组等数据结构.字符串驻留机制及字符串格式化操作 第三章 函数.面向对象.文件操作.深浅拷贝.模块.异常及捕获 第四章 项目打包.类和对象高 ...

最新文章

  1. 秒懂 CountDownLatch 与 CyclicBarrier 使用场景
  2. python中字典和集合的区别_Python中字典和集合学习小结
  3. Oracle PL/SQL语言入门
  4. mysql 算子 谓词_[SQL] SQL 基础知识梳理(六)- 函数、谓词、CASE 表达式
  5. SpringBoot入门详解源码分析
  6. 工业机械类企业官网织梦模板源码
  7. java反编译工具_推荐Java反编译工具luyten、jd-gui
  8. QtCreator 编译时提示 warning C4819 的解决办法
  9. 帝国理工 计算机 金融和管理,计算机毕业生同样研读帝国理工金融工程
  10. ubuntu skill
  11. 桌面被关闭,如何在任务管理器中打开桌面?
  12. 最安全的邮箱大全排名,公司安全邮箱申请如何设置?
  13. 用python画漂亮的网状几何图形
  14. 绝对实践,教你如何成功修改捕鱼达人ipad版 金币
  15. OpenGL基本图元的绘制
  16. js实现整体,局部刷新
  17. 【数据库SQL实战】将id=5以及emp_no=10001的行数据替换成id=5以及emp_no=10005
  18. Spring Boot 基础教程:集成 Knife4j
  19. 普通青年VS文艺青年VS2B青年,爆笑语录!
  20. 基于SpringBoot+MyBatis实现一套电商后台管理系统

热门文章

  1. centos7 网卡命名
  2. 创意油墨飞溅效果的绿树矢量素材
  3. 百度编辑器 ueditor .net开发
  4. Three Tips
  5. 对某目录下的文件按照日期进行排序
  6. 802.1W RSTP
  7. c语言单链表原地转置,不带头结点的单链表的插入,删除,原地转置,判断空,清空,统计节点数目等操作...
  8. 什么是DevSecOps?
  9. Linux SSHD服务安装与维护详解(二)——SSHD调优和fail2ban联动
  10. CTF中基本的Xor解密操作