Qt中的线程编程
在基于操作系统的程序设计中,在处理多任务时,可以有多种方法,但效率较高的当属线程方式,下面就来讨论一下在Qt中如何实现线程编程。
先来说一下什么是线程。线程(thread)是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位,一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈,自己的寄存器环境,自己的线程本地存储。在多核或多CPU,或支持Hyper-threading的CPU上使用多线程程序设计的好处是显而易见,即提高了程序的执行吞吐率。在单CPU单核的计算机上,使用多线程技术,也可以把进程中负责I/O处理、人机交互而常被阻塞的部分与密集计算的部分分开来执行,从而提高了程序的执行效率。
下面就以一个时钟显示的程序来说明在Qt中如何使用线程。在时间显示中,由于显示需要重复不断地刷新,所以可把它放在一个线程中,以节约主线程的资源。本程序基于Qt4.8.7版本制作,程序运行后的界面如下所示。

制作的具体过程如下:
1、启动Qt Creator开发环境,然后点击“New Project”新建项目,会弹出如下所示的对话框。

2、按上图中的默认选项,点击“Choose...”按钮,会弹出下面的对话框。

3、在上图的对话框中,可设置项目的名称和存储的位置,可按自己要求更改或按默认值(注意路径中不要包含中文),点击“下一步”按钮,出现下面的界面。

4、上面的界面为已配置好的环境,可直接点击“下一步”按钮,出现下面的界面。

5、在以上对话框中,可更改项目的细节,可按自己要求更改或按默认值,点击“下一步”按钮,出现下面的界面。

6、在图中直接点击“完成”按钮,结束项目新建的过程,最后得到如下图所示的开发环境。

7、在上图中,单击“项目”中的最后一项“界面文件”左边的箭头,展开该项的内容,然后双击其下的名为“mainwindow.ui”的界面文件,会打开界面设计窗口,如下图所示。

8、在设计界面中,默认有一个空的窗体,现在在左边的控件框中往下找到“Display Widgets”类,然后在其下找到“LCD Number”控件,并把它拖曳至窗体的中央,把长度设置为200像素,高度为60像素,如下图所示。

9、上述设计完成后,点击最左边工具条上的“编辑”切换到程序设计界面,展开“源文件”项,双击主窗体文件“mainwindow.cpp”把它打开,如下图所示。

10、在主程序中,加入对显示控件“LCD Number”的配置,修改后的主函数如下所示:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->lcdNumber->setDigitCount(8); //设置lcd里面的个数,格式是hh:mm:ss,总的是八个。所以设置为8
ui->lcdNumber->setFixedSize(220, 60); //设置大小
ui->lcdNumber->setPalette(Qt::cyan); //设置颜色
ui->lcdNumber->setSegmentStyle(QLCDNumber::Flat); //设置LCD字符为平面显示,无立体感
ui->lcdNumber->setStyleSheet("border: 1px solid black; color: black; background: silver;"); //设置LCD样式
TimeshowThread = new timeshowThread; //新建时间处理线程
connect(TimeshowThread, SIGNAL(sendTime(QString)), this, SLOT(displayTime(QString))); //连接时间显示槽函数
TimeshowThread->start(); //启动线程
}
11、然后加入一个新的函数,内容如下:
void MainWindow::displayTime(QString time) //时间显示槽函数
{
ui->lcdNumber->display(time);
}
12、改好的主程序界面如下所示。

13、 接下来点击“项目”中的“头文件”左边箭头展开该项,双击头文件“mainwindow.h”把它打开,如下图所示。

14、在上述头文件中,加入时间显示槽函数的申明,修改后的头文件如下所示:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "timeshowthread.h" //新加入线程程序的头文件
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
timeshowThread *TimeshowThread; //新建时间显示线程
private slots:
void displayTime(QString); //新加入的槽函数申明
};
#endif // MAINWINDOW_H
15、接下来要新建线程文件,在左边的“源文件”上点击右键,选择“添加新文件...”一项,会弹出如下图的对话框。

16、在上图中选择“C++Source File”一项,然后点击“Choose...”按钮,会弹出如下对话框。

17、在上图中填入新建的线程程序文件名称,这里填入“timeshowthread”,然后点击“下一步”按钮,会弹出如下对话框。

18、在上图中点击“完成”按钮,得到的界面如下所示。

19、在线程文件timeshowthread.cpp中加入以下内容:
#include "timeshowthread.h"
#include <QTime>
timeshowThread::timeshowThread()
{
}
void timeshowThread::run() //线程程序
{
while(1)
{
QDateTime current_date_time = QDateTime::currentDateTime(); //获取当前时间
QString current_time = current_date_time.toString("hh:mm:ss"); //格式化
emit sendTime(current_time); //发射信号
msleep(20); //延时
}
}
20、接下来新建线程头文件,在左边的“头文件”上点击右键,选择“添加新文件...”一项,会弹出如下图的对话框。

21、在上图中选择“C++Header File”一项,然后点击“Choose...”按钮,会弹出如下对话框。

22、在上图中填入新建的线程程序头文件名称,这里填入“timeshowthread”(要与线程程序名称一致),然后点击“下一步”按钮,会弹出如下对话框。

23、在上图中点击“完成”按钮,得到的界面如下所示。

24、在线程头文件timeshowthread.h中加入以下内容:
#ifndef TIMESHOWTHREAD_H
#define TIMESHOWTHREAD_H
#include <QThread>
#include <QString>
class timeshowThread : public QThread
{
Q_OBJECT
public:
timeshowThread(); //申明线程函数
signals:
void sendTime(QString); //申明信号发送函数
protected:
void run(); //申明线程执行函数
public slots:
};
#endif // TIMESHOWTHREAD_H
25、保存所有文件,点击运行按钮运行程序,将得到如前面所示的时钟界面。(注:程序能否正常运行还取决于开发环境的配置)
接下来简要说明一下线程的创建原理。
在Qt中提供有QThread类,要创建一个新的线程,只需定义一个类(如上述头文件timeshowthread.h中定义的timeshowThread),让其继承QThread类即可。然后使用自己创建的类(如timeshowThread)实例化一个对象,也就是用该类创建一个变量(如上述头文件mainwindow.h中的timeshowThread *TimeshowThread;一句及主程序文件mainwindow.cpp中的TimeshowThread = new timeshowThread;一句)。在QThread类中有一个虚函数QThread::run(),要实现自己的线程代码只需要重写该函数即可。最后,通过QThread类中的start()函数可启动这个线程(如TimeshowThread->start();)。另外,由于本例中只进行时间的显示一个任务,所示没有线程结束的操作,时间显示线程将同主线程(UI线程)一起结束。若要进行线程结束的操作,可执行“TimeshowThread->terminate();”即可。
在上面的例子中,还定义了一个信号sendTime(QString)和一个槽函数displayTime(QString time),并把两个量联系在一起(执行connect(TimeshowThread, SIGNAL(sendTime(QString)), this, SLOT(displayTime(QString)));一句)。这样一来, 当在线程中获取了当前时间量后,通过执行“emit sendTime(current_time);”一句,把当前时间量通过信号发送给槽函数displayTime,然后在槽函数中进行显示(执行ui->lcdNumber->display(time);一句)。在线程程序中,通过死循环来不断更新获取当前的时间量,并通过信号发送给槽函数进行显示,这样一来,由于死循环放在了线程中,并不会拖累主线程。但是,虽然死循环放在线程中,但也不能执行的太“满”,否则还是会占用过多的CPU资源,所以在上面的实例中,还是进行了一定时间的休眠(如执行msleep(20);一句)。这里要强调一点,具体休眠多长时间应根据实际的运行情况而定,因为线程通过操作系统来调度,所以休眠时间并不精确,并且休眠时间应以不过度消耗CPU资源为佳(当然,在此例中,由于时间以秒来更新,所以休眠最长可取1秒)。
Qt中的线程编程的更多相关文章
- QT中的SOCKET编程(QT-2.3.2)
转自:http://mylovejsj.blog.163.com/blog/static/38673975200892010842865/ QT中的SOCKET编程 2008-10-07 23:13 ...
- Qt中暂停线程的执行(主线程和工作线程共用一把锁,一旦主线程将它锁上,工作线程就无法运行了,这也是一个办法)
在线程中定义一个信号量: QMutex pause; 把run()函数中循环执行的部分用信号量pause锁住: void run() { while(1) { pause.lock ...
- QT中的SOCKET编程
转自:http://mylovejsj.blog.163.com/blog/static/38673975200892010842865/ QT中的SOCKET编程 2008-10-07 23:13 ...
- Qt中的多线程编程
http://www.ibm.com/developerworks/cn/linux/l-qt-mthrd/ Qt 作为一种基于 C++ 的跨平台 GUI 系统,能够提供给用户构造图形用户界面的强大功 ...
- Qt入门(9)——Qt中的线程支持
Qt对线程提供了支持,基本形式有独立于平台的线程类.线程安全方式的事件传递和一个全局Qt库互斥量允许你可以从不同的线程调用Qt方法.警告:所有的GUI类(比如,QWidget和它的子类),操作系统核心 ...
- QT中的线程与事件循环理解(2)
1. Qt多线程与Qobject的关系 每一个 Qt 应用程序至少有一个事件循环,就是调用了QCoreApplication::exec()的那个事件循环.不过,QThread也可以开启事件循环.只不 ...
- QT中的线程与事件循环理解(1)
1.需要使用多线程管理的例子 一个进程可以有一个或更多线程同时运行.线程可以看做是“轻量级进程”,进程完全由操作系统管理,线程即可以由操作系统管理,也可以由应用程序管理.Qt 使用QThread 来管 ...
- Qt中的串口编程之三
QtSerialPort 今天我们来介绍一下QtSerialPort模块的源代码,学习一下该可移植的串口编程库是怎么实现的. 首先,我们下载好了源代码之后,使用QtCreator打开整个工程,可以看到 ...
- Qt中暂停线程的执行
在线程中定义一个信号量 QMutex pause; 把run()函数中循环执行的部分用信号量pause锁住: void run() { while(1) { pause.lock(); //循环执行的 ...
- Qt中暂停线程的执行(利用QMutex,超级简单明了)
在线程中定义一个信号量: QMutex pause;把run()函数中循环执行的部分用信号量pause锁住: void run() { while(1) { pause.lock(); //循环执行的 ...
随机推荐
- [Unity]关于Physic Material,物理碰撞
制作游戏时发现了一些问题,主角身上有刚体(rigbody) 在地面移动时没有什么太大的问题,但是一旦在下落时按住方向键,就会出现角色贴在墙上不下来的问题 通过其他例子发现使用了Physic Mater ...
- P1886 滑动窗口 /【模板】单调队列
滑动窗口 /[模板]单调队列 题目描述 有一个长为 \(n\) 的序列 \(a\),以及一个大小为 \(k\) 的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小 ...
- PHP 调用外部接口
//1.类中定义静态方法 class FtpService{ /** * 请求外网 * @param $url 外网接口url * @param bool $params 参数,拼接字符串 post请 ...
- vue 基础 v-text v-html v-model v-cloak v-bind
v-text 纯文本绑定 v-html 会解析html标签 <p v-html="rawHtml"></p> var a=new Vue({ el:&q ...
- LinuxK8S集群搭建三(部署dashboard)
系统环境: CentOS 7 64位 准备工作: 通过虚拟机创建三台CentOS服务器,可参照之前的文章192.168.28.128 --master192.168.28.130 --node0119 ...
- python代码编译总结-用于代码加密
基于一个自废武功式的决定,服务需要做成标准件在客户服务器上运行,因此调研了python代码加密的相关内容.py的代码混淆没有被采用,而是采用cython编译成二进制文件进而掩盖源码的方式对代码加密. ...
- 加密算法和hash
随着安全问题越来越被重视,公司也全面替换了HTTP为HTTPS.2015年iOS9的ATS到今年苹果更是放出话来,2017年全面支持HTTPS,不支持的App,在审核的时候可能会遇到麻烦.鉴于此,我有 ...
- 成品直播源码,Flutter 夜间模式 全局字体
成品直播源码,Flutter 夜间模式 全局字体 import 'package:flutter/material.dart';import 'package:flutter_widget/route ...
- [转]c#特性(Attribute)学习总结1
特性是用于在运行时传递程序中各种元素(类.方法.结构.枚举.组件等)的行为信息的声明性标签. 官方的解读不好理解,举个常用的例子,平时会在类的上面加上[Serializable],Serializab ...
- 《【转载】ChatGPT创始人,给我们上的8堂课》 回复
<[转载]ChatGPT创始人,给我们上的8堂课> https://tieba.baidu.com/p/8276644432