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(); //循环执行的 ...
随机推荐
- 解决报错Could not satisfy explicit device specification '' because the node was colocated with a group of nodes that required incompatible device '/device:GPU:0'
sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))改为如下:sess = tf.Session(config=tf. ...
- x-sheet 开发系列教程:初始化配置
介绍 x-sheet 是一款高性能 Web JavaScript Canvas 电子表格,之前小编写过一篇 x-sheet 入门体验,简单介绍了一下如何使用 x-sheet.这次我们继续深入一下,了解 ...
- git提交到代码到远程仓库,合并分支提示entirely different commit histories(备忘)
最近提交代码到github,合并分支的时候提示"master and main are entirely different commit histories" master为本地 ...
- PS技能之电子签名+修白牙齿
PS技能 NO.1 电子签名 有时候由于时空的限制,本人无法签字,那么电子签名就有了它的作用啦![注:谨慎使用] 亲试有效的教程,现在就是做笔记的时候啦! 教程链接如下: https://blog.c ...
- CS客户端 App.Config更新问题
appconfig更新必须要重启才可以 这个方法为热更新不用重新启动 public void ModifyConfig(string serverName, string dbName, strin ...
- .NET Framework 中对webapi进行jwt验证
最近在项目中对webapi进行了jwt验证,做一个记录 有关于jwt生成和验证token的操作全部记录在jwthelper.cs文件中: /// <summary> /// 授权JWT类 ...
- 利用拉格朗日乘子法从最优化问题中推导出KKT条件
优化问题的一般形式 在优化问题中,我们将其一般形式定义为有约束(不等式约束.等式约束)的最小化优化问题,其具体定义如下: \[\begin{array}{ll} \min _{x} & f_{ ...
- nestjs mongoose关联查询
nestjs,mongoose关联查询网上搜不到了,查看了nest/mongoose.d.ts文件,分享一波 user.model.ts import { Prop, Schema, SchemaFa ...
- gitlab 安装以及汉化
转载 https://www.bbsmax.com/A/pRdBAg465n/
- Android使用volley发送带参数的post请求
用参数方式可以解决E/Volley: [777] BasicNetwork.performRequest: Unexpected response code 500 for XXXXX 1.Strin ...