基于Qt的多窗体快速并行图形绘制方法研究

2019-01-22 06:54覃仁谅宁芊严华
现代计算机 2018年35期
关键词:窗体线程绘图

覃仁谅,宁芊,严华

(四川大学电子信息学院,成都 610065)

0 引言

数据可视化作为数据分析的一种重要的技术,能够有效地提高工程的效率和准确性,已经被广泛用于多个领域[1],特别是在一些复杂工业领域,工程上需要采用多窗体图形显示来同时对多个条件变量进行实时监测。例如,在变电站综合分析系统中,需要对电流、电压、温度等实时数据进行实时显示和分析,以实现对数据采集设备和采集状态的监控[2];在地震前兆台网监控系统中,需要同时对多个前兆仪器的采集数据进行实时显示,以便于仪器管理人员对仪器进行监测和监测预报人员对数据进行观测[3];在情报雷达显控系统中,需要对雷达P显、B显、E显、A显等多种二维显示方式进行多窗体同时显示,以便于雷达操作人员对雷达探测结果进行分析,从而使他们做出更加精准的判断和决策[4]。

数据采集技术的发展和工程应用的需求,使得数据采样频率越来越快、数据规模也越来越大,单个图形显示窗体所需时间也越来越长,因此对多窗体图形绘制的效率也提出了更高的要求。传统方法在绘制多窗体图形时,单个数据帧的数据图形化总时间随着数据图形窗体数量增加而线性增加,从而导致数据图形绘制效率与实时性降低,难以满足高实时性的多窗体图形显示需求。

随着CPU多核并行技术的发展,CPU多核并行计算已经被广泛用于多个领域[5]。通过在多个CPU核上进行负载分担来提高系统的性能。由于多窗体图形显示数据的独立性,即多个窗体图形数据之间不具有相干性,因此针对传统多窗体图形绘制效率低的问题,结合双缓冲绘图技术[6],提出了基于Qt的多窗体快速并行图形绘制方法。该方法利用CPU多核多线程并行计算能力实现对多窗体图形的绘制,提高了多窗体图形绘制的效率,大大减少了单个数据帧的数据可视化总时间。

1 绘图系统、线程机制、信号与槽机制

Qt作为一种基于C++的跨平台GUI(Graphical Us⁃er Interface)系统,能够给应用程序开发者提供建立图形用户界面所需的所有功能。同时,Qt是纯面向对象的,由于其具有良好的封装机制,模块化程度非常高,有良好的可重用性,大大方便了用户的开发。

1.1 QQtt绘图系统

Qt绘图系统主要由三部分组成,分别为QPainter类、QPaintDevice类、QPaintEngine类。其中QPainter类用于执行绘图操作,相当于画家,提供drawPixmap、drawImage等各种绘图命令,QPaintDevice类相当于画布,提供 QImage、QPixmap、QBitmap、QPicture等画布类接口,QPaintEngine类提供了QPainter类用来绘制到不同类型设备的接口,是基本QPainter类绘图命令的具体实现。Qt绘图系统组成关系如图1所示。

图1 Qt绘图系统组成关系

1.2 QQtt线程机制

Qt线程主要由线程类和线程同步类组成,其中QThread是线程类接口,提供了一个与平台无关的方法来管理线程,线程同步类包括QMutex、QSemphore、QWaitCondition、QReadWriteLock等,提供了线程同步接口。在Qt图形用户界面的应用程序中,GUI线程是图形用户界面的主线程,是Qt中唯一可以执行GUI相关操作的线程,但它可以同时拥有一个或者多个非GUI线程作为工作线程,以便于处理应用程序中其他耗时操作。

1.3 QQtt信号与槽机制

信号与槽机制是Qt的核心机制,主要用于对象间的通信。它可以通过已有的信号和槽或自定义的信号和槽,将互不了解的对象绑定在一起。信号与槽的连接方式主要包括自动连接、直接连接、队列连接、队列阻塞连接等。一个信号和槽连接后,每当一个对象发射该信号时,就会自动调用该槽函数,特别是信号与槽机制可以支持跨线程的连接,处于不同线程的对象也可以使用信号与槽进行连接,从而可以实现线程间的通信。

2 传统的多窗体图形绘制方法

在传统的多窗体图形显示系统中,多窗体图形显示的数据由数据采集设备实时提供,并且通过串口或网络等传输方式将采集的数据以数据帧的形式发送给显控系统。显控系统采用一个单独工作线程来实时获取数据帧,而每个数据帧都是一个复杂的数据结构,数据帧中封装了多窗体图形显示所需要的数据。通过解析该数据帧获得每个显示窗体所需要的显示数据。随后多个窗体按照串行方式进行多窗体图形绘制,即先完成当前窗体图形的数据处理、数据坐标映射、内存绘图、输出窗体图形等操作后,再去执行下一个窗体图形绘制操作,最终完成多窗体图形的绘制。算法实现的流程如图2所示。

图2 传统的多窗体图形绘制方法

图形绘制采用双缓冲绘图技术,其主要由内存绘图和图形输出两部分组成。通过多图层和贴图的方法实现图形绘制[7],不仅能够解决图形界面闪烁问题,而且也能够加快图形的绘制速度。

但传统的多窗体图形绘制方法仅采用一个界面主线程来串行完成多个窗体图形的绘制。随着数据的规模越来越大,绘图任务越来越复杂,则单个窗体图形绘制时间越长。此时在多窗体图形显示情况下,单个数据帧的数据图形化总时间随着绘图窗体数量的增加而线性增加,严重影响到整个图形显示系统的效率,导致数据图形的实时性降低,从而不能满足系统的需求。因此,在传统的多窗体图形绘制的基础上提出了基于Qt的多窗体快速并行图形绘制方法。

3 快速并行的多窗体图形绘制方法

3.1 多窗体图形显示的数据特点

数据采集的一次信息数据封装在一个数据帧中,界面主线程通过解析该数据帧,将多个窗体图形显示数据分别存放在不同的缓冲区,接着分别相互独立的进行数据处理、数据坐标映射、内存绘图、输出图形等操作,因此多窗体图形显示的数据之间没有相干性,即一个窗体图形显示的数据不依赖于其他窗体图形显示的数据。

3.2 QQtt绘图引擎特点

在具有图形用户界面的Qt应用程序中,由于GUI相关操作只能在界面主线程中执行,因此输出图形操作只能在界面主线程完成,而数据处理、数据坐标映射、内存绘图等操作可以搬移到其他工作线程上执行,特别是内存绘图操作。QImage和QPixmap作为Qt的画布类接口,在功能上有着不同的地方。QImage是为I/O设计和优化的,可用于直接像素访问和操作,在QImage上使用QPainter画家类时,内存绘图操作是可以在非GUI线程中执行,而不需要在GUI线程中处理,从而可以很大幅度提高图形界面的响应速度;QPix⁃map在屏幕显示图像方面进行了相关的设计优化,从而使得采用QPixmap进行输出图形具有更好的显示效果。此外,GUI线程与非GUI线程可以通过Qt信号与槽机制实现线程间通信。

3.3 LLiinnuuxx多线程特点

Linux操作系统中提供的LinuxThreads库是内核级方式,库中的线程其实是一种轻权进程LWP[8]。Linux系统中,Qt线程的实现采用了LinuxThreads库。在CPU多核处理器上,操作系统为了充分利用CPU多核资源,同一应用程序中的多个线程任务将在操作系统的调度下分配到CPU的多个核上进行处理。通过CPU绑定技术[9],将多线程绑定在不同CPU核上,从而实现多线程任务真正的并行。

3.4 基于QQtt的多窗体快速并行图形绘制方法

结合多窗体图形显示的数据特点、Qt绘图引擎特点以及Linux多线程特点,当数据处理、数据坐标映射、内存绘图等任务耗时程度较大时,多窗体图形绘制通过利用CPU多核多线程并行计算能力,实现多窗体图形数据处理、数据坐标映射、内存绘图的并行化计算,从而提高多窗体图形绘制的效率。因此提出了一种基于Qt的多窗体快速并行图形绘制方法。

(1)绘图工作线程的并行化操作

每个窗体图形绘制都对应一个绘图工作线程,利用CPU绑定技术让绘图工作线程分别运行在不同CPU核上。而每个绘图工作线程主要完成数据处理、数据坐标映射、内存绘图等并行化操作,同时与界面主线程进行线程间通信。算法实现的流程如图3所示。

当界面主线程解析数据帧后,则会向每个绘图工作线程发送startPaint信号,绘图工作线程接收到start⁃Paint信号后,开始进行获取显示数据、数据处理、数据坐标映射、内存绘图等操作,当完成这些操作后,绘图工作线程向界面主线程发送finishPaint信号,通知界面主线程进行图形输出操作。即将耗时的内存绘图等操作放在绘图工作线程上执行,而界面主线程则只负责多个窗体的图形输出操作以及其他UI操作。

图3 绘图工作线程的并行化操作

(2)图形的输出

双缓冲绘图机制主要包括内存绘图和内存拷贝到显存操作,而图形的输出是属于内存拷贝到显存操作。由于图形显示具有图形缩放、图形拖动等功能,因此内存拷贝到显存操作需要根据当前窗体的显示内容来进行选择性内存拷贝,绘图内存与显示窗体之间的映射如图4所示。

图4 绘图内存与显示窗体之间的映射

具体实现方法为:假设当前显示窗体为(wX,xY,wWidth,wHeight),其中(wX,xY)表示当前显示窗体可见范围的左顶点坐标,wWidth和wHeight分别表示当前显示窗体可见坐标范围的宽和高,当前显示窗体相对应的需要拷贝的绘图内存块为(mX,mY,mWidth,mHeight),其中(mX,mY)表示当前拷贝绘图内存块的左顶点坐标,mWidth和mHeight分别表示当前需要拷贝的绘图内存块的宽和高。

当绘图工作线程在QImage绘图内存上完成内存绘图工作后,界面主线程先通过绘图内存块与显示窗体之间的映射关系,即由当前显示窗体(wX,xY,wWidth,wHeight),通过映射公式计算出当前需拷贝的绘图内存块(mX,mY,mWidth,mHeight),接着通过调用 QImage的函数接口,将绘图内存块(mX,mY,mWidth,mHeight)缩放至显示窗体大小,随后将QImage对象转换成QPix⁃map对象,最后通过调用Qt绘图引擎的API函数,将QPixmap内存块拷贝至显存进行图形显示,从而实现图形的输出。绘图内存块与显示窗体之间的映射公式如式(1)、式(2)、式(3)、式(4)所示。

其中,mWidth和mHeight分别表示QImage绘图内存的最大宽度、最大高度,wXLower和wXUpper分别表示显示窗体横轴X最小值、最大值,wYLower和wYUpper分别表示显示窗体纵轴Y的最小值、最大值,wScale表示当前图形缩放比例。

(3)多窗体快速并行图形绘制的实现

根据多窗体快速并行图形绘制的思想,在多线程进行CPU绑定后,若获取的数据帧为DataFrame,窗体数量为FormCount,解析数据帧得到的显示数据为Raw⁃Data[FormCount][DataSize],经数据处理后为Daat[Data⁃Size],数据坐标映射后为MapData[DataSize]。实现的伪代码如下:

1.Begin

2.getDataFrame(DataFrame)

3.parseDataFrame(DataFrame,RowData)

4.loop i from 0 to FormCount-1 in parallel processing

5.Data=dataProcess(RowData[i,DataSize])

6. loop j from 0 to DataSize-1 in step of 1

7. MapData[j]=map(Data[j])

8. end of loop

9.drawImage(MapData)

10.end of loop

11.outputGraphics()

12.End

其中,getDataFrame用于获取数据帧,parse⁃DataFrame函数用于解析数据帧获得多窗体图形显示的数据,dataProcess函数用于对数据进行处理,map函数用于对处理后的数据进行坐标映射,drawQImage函数用于根据得到的MapData数据进行内存绘图操作,outputGraphics函数用于将内存块拷贝至显存,以实现图形输出。

分析上述伪代码可知,每个显示窗体的数据相互独立,因此可以将多个显示窗体的耗时操作由不同的工作线程并行处理计算,而界面主线程只负责多个图形的输出操作以及其他UI操作,这样不仅可以提高多窗体图形绘制的效率,而且很大程度上提高了图形界面的响应速度。

根据上述的分析,多窗体快速并行图形绘制算法主要由以下4个步骤实现。

(1)数据帧的获取:为了获取实时的数据帧,同时也为了提高图形界面的响应速度,数据帧的获取操作由单独的工作线程来执行。

(2)数据帧的解析:为了适应多窗体图形的并行化操作,解析得到的多个窗体显示数据将分别存放在不同缓冲区。

(3)多个窗体图形绘制的并行化:不同窗体图形显示的数据处理、数据坐标映射、内存绘图等操作,将由不同的绘图工作线程来执行。

(4)图形的输出:绘图工作线程与界面主线程之间采用队列阻塞式的信号与槽机制,即先完成内存绘图的显示窗体将由界面主线程先执行图形的输出操作,直到完成所有窗体图形的显示。

基于Qt的多窗体快速并行图形绘制方法的实现流程如图5所示。

图5 基于Qt的快速并行图形绘制方法实现流程

4 实验结果

4.1 仿真环境

本文仿真在Linux、Intel Core八核i7-67003.4GHz、16GB内存、Intel HD Graphics 530下进行。绘图引擎为Qt5.6.1,编程环境为 Qt Creator 4.0.1,编程语言为C++。为了便于对两种多窗体图形的绘制方法进行比较,多窗体图形以直角坐标系上绘制二维曲线图形为例。

4.2 绘制效率对比

绘制效率的对比以绘制时间和相对加速比作为比较标准,其中绘制时间为单个数据帧的图形化总时间,而相对加速比为单个数据帧的传统方法绘制时间与快速并行方法绘制时间的比值。使用两种绘制方法分别测试了不同绘制数据个数下的多窗体图形绘制时间。

绘制数据个数为2000时,多窗体图形绘制时间的对比如表1和图6所示。绘制数据个数为4000时,多窗体图形绘制时间的对如表2和图7所示。绘制数据个数为8000时,多窗体图形绘制时间的对比如表3和图8所示。图9表示不同绘制数据个数下,相对加速比与显示窗体个数之间关系的对比。

表1 两种方法的绘制效率比较(数据个数:2000)

表2 两种方法的绘制效率比较(数据个数:4000)

表3 两种方法的绘制效率比较(数据个数:8000)

针对相同数据个数下的不同数量显示窗体,对比传统多窗体图形绘制方法和快速并行多窗体图形绘制方法的绘制时间可以看出:随着显示窗体数量的增加,快速并行的多窗体图形绘制时间明显小于传统多窗体图形的绘制时间。这是由于快速并行绘制方法将多窗体图形的内存绘图等耗时操作交给绘图线程,而绘图线程绑定在不同CPU核上,从而提高了多窗体图形的绘制效率。

针对相同数据个数下的不同数量显示窗体,对比相对加速比可以看出:随着显示窗体数量的增加,快速并行绘制方法的相对加速比不断增加,但增加的速率逐渐变慢。这是由于随着显示窗体数量的增加,界面主线程的图形输出队列逐渐增长,导致并行绘制效率提升缓慢,因此基于Qt的多窗体快速并行图形绘制方法中的图形输出操作应具有较低的耗时程度。

图6 绘制时间对比直方图(数据个数为2000)

图7 绘制时间对比直方图 (数据个数为4000)

图8 绘制时间对比直方图 (数据个数为8000)

图9 相对加速比曲线图

在图9中,针对不同数据个数下的相同数量显示窗体,对比相对加速比可以看出:单个窗体图形绘制数据个数越大,则快速并行绘制方法的相对加速比越大。这是由于单个窗体图形绘制数据个数越大,则可并行任务的耗时程度越大,此时可以获得更好的并行绘制效率。

4.3 系统资源利用率对比

系统资源利用率的对比以CPU核使用数为比较标准。在Linux系统中,通过top命令查看图形界面应用程序使用CPU核的数量,两种多窗体图形绘制方法的CPU核使用数量如表4所示。

表4 两种绘制方法的CPU核使用数比较

从表4可看出,在窗体个数为6时,快速并行绘制方法的CPU核使用数是传统绘制方法的4倍。这是由于传统绘制方法只有2个线程,即获取数据帧线程和界面主线程,这2个线程会在操作系统的调度下随机运行在2个CPU核上,而快速并行绘制方法除了以上2个线程外,还有6个绘图线程,这8个线程分别绑定在不同CPU核上。因此,在绘制多窗体图形时,本文提出的方法的CPU核利用率明显高于传统多窗体图形绘制方法,大大提高了系统资源利用率。

5 结语

本文结合多窗体图形显示的数据特点、Qt绘图引擎的特点以及Linux多线程的特点,在双缓冲绘图的基础上,利用CPU多核多线程的并行计算能力,提出了基于Qt的多窗体快速并行图形绘制方法。实验表明,基于本文方法的多窗体图形的绘制,有效地减少了单个数据帧的数据图形化总时间,大大提高了多窗体图形的绘制效率,同时也提高了系统资源的利用率。目前该方法已经成功应用于某雷达显控系统,并取得了良好的效果。

猜你喜欢
窗体线程绘图
“禾下乘凉图”绘图人
5G终端模拟系统随机接入过程的设计与实现
实时操作系统mbedOS 互斥量调度机制剖析
浅析体育赛事售票系统错票问题的对策研究
试谈Access 2007数据库在林业档案管理中的应用
垂涎三尺
关于Access中切换面板的问题与解析
绘图机器人
WinCE.net下图形用户界面的开发
Java的多线程技术探讨