【为什么要用多线程?】

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

【Linux有线程的概念吗?】

传统的UNIX系统也支持线程的概念,但一个进程里只允许有一个线程,这样多线程就是多进程。Linux下的Posix线程(pthreads)是一种轻量级的进程的移植性实现,线程的调度由内核完成,每个线程都有自己的编号。如果使用线程,总体消耗的系统资源较少,线程间通信也比较容易,在工程中推荐使用线程。

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

  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代码

 1 #ifndef THREAD_H
 2 #define THREAD_H
 3
 4 #include <QThread>
 5 #include <iostream>
 6
 7 class Thread : public QThread
 8 {
 9     Q_OBJECT
10 public:
11     Thread();
12     void setMessage(QString message);
13     void stop();
14
15 protected:
16     void run();
17     void printMessage();
18
19 private:
20     QString messageStr;
21     volatile bool stopped;
22 };
23
24 #endif // THREAD_H

注:

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

thread.cpp代码

 1 #include "thread.h"
 2 #include <QDebug>
 3
 4 Thread::Thread()
 5 {
 6     stopped = false;
 7 }
 8
 9 void Thread::run()
10 {
11     while(!stopped)
12     {
13         printMessage();
14     }
15     stopped = false;
16 }
17
18 void Thread::stop()
19 {
20     stopped = true;
21 }
22
23 void Thread::setMessage(QString message)
24 {
25     messageStr = message;
26 }
27
28 void Thread::printMessage()
29 {
30     qDebug()<<messageStr;
31     sleep(1);
32 }

注:

  • QTread提供了一个terminate()函数,该函数可以再一个线程还在运行的时候就终止它的执行,但不推荐用terminate(),因为terminate()不会立刻终止这个线程,该线程何时终止取决于操作系统的调度策略,也就是说,它可以随时停止线程执行而不给这个线程自我清空的机会。更安全的方法是用stopped变量和stop()函数,如例子所示。
  • 调用setMessage()让第一个线程每隔1秒打印字母“A”,而让第二个线程每隔1秒打印字母“B”。
  • 线程会因为调用printf()而持有一个控制I/O的锁,多个线程同时调用printf()在某些情况下回造成控制台输出阻塞,而用qDebug()作为控制台输出一般不会出现上述问题。

threaddialog.h代码

 1 #ifndef THREADDIALOG_H
 2 #define THREADDIALOG_H
 3
 4 #include <QPushButton>
 5 #include <QDialog>
 6 #include <QCloseEvent>
 7 #include "thread.h"
 8
 9 class ThreadDialog : public QDialog
10 {
11     Q_OBJECT
12
13 public:
14     ThreadDialog(QWidget *parent=0);
15
16 protected:
17     void closeEvent(QCloseEvent *event);
18
19 private slots:
20     void startOrStopThreadA();
21     void startOrStopThreadB();
22     void close();
23
24 private:
25     Thread threadA;
26     Thread threadB;
27     QPushButton *threadAButton;
28     QPushButton *threadBButton;
29     QPushButton *quitButton;
30 };
31
32 #endif // THREADDIALOG_H

threaddialog.cpp代码

 1 #include "threaddialog.h"
 2
 3 ThreadDialog::ThreadDialog(QWidget *parent) : QDialog(parent)
 4 {
 5     threadA.setMessage("A");
 6     threadB.setMessage("B");
 7
 8     threadAButton = new QPushButton(tr("Start A"), this);
 9     threadAButton->setGeometry(10, 30, 80, 30);
10     threadBButton = new QPushButton(tr("Start B"),this);
11     threadBButton->setGeometry(110, 30, 80, 30);
12     quitButton = new QPushButton(tr("Quit"), this);
13     quitButton->setGeometry(210, 30, 80, 30);
14     quitButton->setDefault(true);
15
16     connect(threadAButton, SIGNAL(clicked()), this, SLOT(startOrStopThreadA()));
17     connect(threadBButton, SIGNAL(clicked()), this, SLOT(startOrStopThreadB()));
18     connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
19 }
20
21 void ThreadDialog::startOrStopThreadA()
22 {
23     if(threadA.isRunning())
24     {
25         threadAButton->setText(tr("Stop A"));
26         threadA.stop();
27         threadAButton->setText(tr("Start A"));
28     }
29     else
30     {
31         threadAButton->setText(tr("Start A"));
32         threadA.start();
33         threadAButton->setText(tr("Stop A"));
34     }
35 }
36
37 void ThreadDialog::startOrStopThreadB()
38 {
39     if(threadB.isRunning())
40     {
41         threadBButton->setText(tr("Stop B"));
42         threadB.stop();
43         threadBButton->setText(tr("Strat B"));
44     }
45     else
46     {
47         threadBButton->setText(tr("Start B"));
48         threadB.start();
49         threadBButton->setText(tr("Stop B"));
50     }
51 }
52
53 void ThreadDialog::closeEvent(QCloseEvent *event)
54 {
55     threadA.stop();
56     threadB.stop();
57     threadA.wait();
58     threadB.wait();
59     event->accept();
60 }
61
62 void ThreadDialog::close()
63 {
64     exit(0);
65 }

注:

  • 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代码

 1 #include "threaddialog.h"
 2 #include <QApplication>
 3
 4 int main(int argc, char *argv[])
 5 {
 6     QApplication app(argc, argv);
 7     ThreadDialog *threaddialog = new ThreadDialog;
 8     //threaddialog->exec();
  //threaddialog->exec();
       threaddialog->show();//否则关闭界面后线程不能正常退出
 9     return app.exec();10 }

注:

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

Qt多线程学习:创建多线程相关推荐

  1. C#多线程学习(四) 多线程的自动管理(线程池) (转载系列)——继续搜索引擎研究...

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  2. C#多线程学习(五) 多线程的自动管理(定时器) (转载系列)——继续搜索引擎研究...

    Timer类:设置一个定时器,定时执行用户指定的函数.               定时器启动后,系统将自动建立一个新的线程,执行用户指定的函数. 初始化一个Timer对象: Timer timer ...

  3. C#多线程学习(一) 多线程的相关概念(转自xugang的blog)

    C#多线程学习(一) 多线程的相关概念 什么是进程? 当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源. 而一个进程又是由多个线程所组成的. 什么是线程? 线程 ...

  4. [转载]C#多线程学习(一) 多线程的相关概念

    原文地址:http://www.cnblogs.com/xugang/archive/2008/04/06/1138856.html 什么是进程? 当一个程序开始运行时,它就是一个进程,进程包括运行中 ...

  5. VC++中多线程学习(MFC多线程)一(线程的创建、线程函数如何调用类成员呢?如何调用主对话框的成员?、MFC中的工作线程和界面线程的区别)

    这里废话不多讲了,因为项目原因,需要开启线程进行处理,在不了解线程的情况下,直接百度一下,然后就使用了,结果可想而知,出现了异常,所以花了一天时间系统学习一下多线程,这里主要是针对win32编程方面的 ...

  6. java多线程w3c_Java创建多线程的三种方式

    前言 这篇文章主要讲述线程的概念.组成.Java创建多线程的三种方式以及线程的类型. 线程概念 线程和进程的区别 **进程:**正在运行的程序,例如:你打开 的qq音乐.exe程序,其由PCB(进程控 ...

  7. java 创建多线程_Java创建多线程

    Java创建多线程 下一节> 到目前为止,我们仅用到两个线程:主线程和一个子线程.然而,你的程序可以创建所需的更多线程.例如,下面的程序创建了三个子线程: // Create multiple ...

  8. 多线程一,什么是多线程,创建多线程的几种方式

    文章目录 1 多线程相关概念 2 多线程概念 3 多线程优缺点 4 多线程实现方式 5 实现runnable和callable的区别 6 继承thread和实现runnable接口的区别 7 多线程匿 ...

  9. 【java多线程学习】多线程的基本概念

    今天开始系统的学习了java多线程有关的基础知识,大致先分为三个步骤:多线程的基本概念,多线程的两种使用方法(继承Thread类.实现Runable接口),线程的同步.这里先记录下下多线程的基本概念. ...

  10. [转]C#多线程学习(四) 多线程的自动管理(线程池)

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

最新文章

  1. 【Bootstrap+JSP+Mysql学习笔记(二)】开发环境配置(二)
  2. C# 简单方式解压Zip文件/使用VS2019自带功能
  3. 【算法】剑指 Offer 12. 矩阵中的路径
  4. 一行Python代码计算两点间曼哈顿距离
  5. 计算机硬件技术基础 统计字符串strl中字符'a'的个数,汕头大学工学院830计算机基础综合历年考研真题202p.doc...
  6. NLP—1.自然语言处理的基础任务与应用
  7. 机器学习:残差学习、RNN、GAN、迁移学习、知识蒸馏
  8. winhex添加删除字节
  9. B - Ternary Logic
  10. 2022-2027年中国肺炎疫苗行业市场运行现状及投资战略研究报告
  11. STM32CubeMX学习--ThreadX_UART
  12. ROS-3DSLAM --开篇:综述
  13. Pytorch版YOLOv4训练步骤(二)
  14. 开关电源IC的选择要求
  15. 基于无线发射接收的物体远离报警器的设计
  16. 肝病患者关爱与病例管理
  17. 【DFS经典例题】2n皇后问题
  18. Ruby字符串处理函数
  19. 数据仓库建模篇-维度剑魔
  20. 《国民教育大考察》百度应用创新大奖赛 游戏类 二等奖

热门文章

  1. Consul负载均衡策略
  2. oracle修改字段名称 试图删除被依赖列_oracle 添加 删除列 修改表名字 ;加注释 异常解释...
  3. aix下mysql启动命令_AIX常用操作命令
  4. 数据中心节能专题—他山之石可以攻玉
  5. 抛弃市电!微软建成世界首座天然气数据机房:能耗大减
  6. centos组件显示乱码,centos组件显示乱码_解决CentOS下中文显示乱码
  7. MAT之GUI:GUI的方式创建/训练/仿真/预测神经网络
  8. System之Ubuntu:VMware虚拟机 Ubuntu安装详细过程(图文教程,最强攻略,步骤详细,建议收藏)
  9. ML/DL:关于机器学习、深度学习算法模型的选择
  10. 成功解决 gpu_device.cc:1120] Creating TensorFlow device (/device:GPU:0) - (device: 0, name: GeForce 94