基于多线程的环境监控系统下位机的设计
2017-05-11
为提高环境监控系统的稳定性,节约系统资源,提出了一种由下位机、传输网络和上位机组成的环境监控系统的设计方案,详细介绍了该系统中下位机的硬件及软件设计。该下位机硬件以ARM9处理器S3C2410为核心,软件采用多线程应用程序同时处理多个任务,并采用信号量和互斥量实现线程间的同步。实际应用表明,该系统运行稳定,提高了系统效率。
0引言
随着国民经济及工业技术的发展,环境保护越来越受到重视。现在市场上已经出现了多种环境监控系统,但性能不稳定。现场监控终端大多采用工控机或单片机,前者抗干扰性能好,但成本较高;后者处理能力低,人机界面不友好,不利于现场人员的监控管理。针对上述问题,笔者设计了一种基于多线程的环境监控系统。该系统采用多线程技术有效地实现了监控过程中数据的采集与存储、实时数据显示、下位机(监控终端)与上位机(监控中心)的通信、实时报警等功能。本文重点介绍该系统下位机的设计。
1系统总体结构
基于多线程的环境监控系统由现场监控终端(下位机)、传输网络、监控中心(上位机)3个部分组成,其结构如图1所示。
图1基于多线程的环境监控系统结构
下位机是一个基于A RM9的嵌入式系统,用于定时采集、处理、存储被监测的特征数据。经过下位机处理后的数据,按照相关协议,经GPRS模块发送给上位机。上位机由一台PC机担任,负责接收多个下位机发送的数据,并对这些数据进行分析、处理和显示。环保部门可通过上位机监控其辖区内的污染排放状况。上位机基于VB. NET开发。
2下位机硬件设计
下位机的硬件核心部分由S3C2410、NandFLASH和SDRAM组成,如图2所示。S3C2410是三星公司生产的一款基于ARM920T内核的32位RISC嵌入式微处理器,带有独立的16 KB指令Cache和16 KB数据Cache、LCD控制器、RAM控制器、N and FLASH控制器、并行I/ O口、8路10位ADC,其运行频率可达203 MHz.8位64 MB的Nand FLASH选用的芯片为K9F1208, 64 MB的SDRAM由2片HY57V561620组成。下位机通过以太网控制器CS8900A扩展了一个网口,数据既可以通过无线传输,也可以通过有线传输;通过I/ O接口扩展了8个DI口(数字量输入)、4个AI口(模拟量输入)、4个DO口(数字量输出),下位机通过这些接口与被监控设备通信。
图2下位机硬件组成
3下位机的需求与结构设计
下位机定时采集、处理现场数据,并存储在数据库中,把实时数据发送给上位机,并响应上位机发送的控制命令。因此,下位机需要同时处理多个任务,这些任务并发执行。若使用单线程来完成这些任务,则需要使用多个定时器来触发,而过多的定时器会导致系统不稳定。Window s是抢先式多任务的操作系统,启动了一个应用程序就等于启动了一个进程。一个进程通常拥有一个线程,在系统资源管理中,每一个线程被分配一定的时间片。采用多线程的设计方法可以使程序拥有多个线程,这样程序就能同时处理更多的任务。因此,若使用多个进程来协作完成,能避免上述缺点且系统比较稳定,但系统对进程的频繁调度会占用过多资源,程序的可读性也不好。
笔者采用一种并行的、多线程方案能够很好地处理多个任务,并充分节约系统资源。该方案中,下位机有5个线程:GU I线程、复位线程、数据采集与存储线程、网络通信线程、决策线程。其中GU I线程为主线程,负责界面处理、系统数据的初始化以及创建子线程等任务;复位线程、数据采集与存储线程、网络通信线程是后台的工作线程,通过优先级调度、线程同步等机制保证能可靠执行现场数据采集、存储、发送、显示等任务。复位线程在启动后循环地对看门狗操作,不作为任务处理线程。任务线程之间的关系如图3所示。
图3任务线程之间的关系
4多线程技术在系统中的应用
4. 1线程的创建
Linux环境下,使用pthread_cr eate()函数创建一个新线程,默认情况下主线程会等待被创建的子线程执行结束,得到子线程的返回结果然后再继续往后执行。实时监控程序的子线程都是循环执行的,不需要运行结束后归并到主线程中,需设置其属性为PT HREAD _ CREATE _DETACHED.根据子线程的重要性进行优先级设置,确保重要线程优先执行。子线程的优先级从高到低依次为复位线程、数据采集与存储线程、决策线程、网络通信线程。
线程的创建、设置伪代码如下:
void * thr ead_wat chdog(void * arg); / /复位线程函数
void * thr ead_collect ion(void * arg); / /数据采集与存储线程函数
void * thr ead_communi cat ion(void * arg); / /网络通信线程函数
void * thr ead_decis e(void * arg); / /决策线程函数
int dat a[ 12] ; / /数据缓冲区,用于存放线程间共享的数据函数
main()
{
/ /初始化工作
……
pthread_t wat chd og; / /线程号
pthread_t collect ion;
pthread_t commun ication;
pthread_t deci se;
pthread_at t r_init(); / /初始化线程属性
pthread_at t r_setdetach st at e(); / /不对线程进行重新归并
pthread_at t r_set s ched param(); / /设置线程的优先级
sem_init(); / /对相关信号量进行初始化
pth read_creat e(); / /创建新线程
/ /启动GUI程序
……
}
4. 2线程的同步机制
同步机制是否合理是多线程应用程序运行是否稳定的关键。在程序设计时,需考虑到可能引起数据毁坏的多线程数据访问冲突以及如何使用同步技术避免这种冲突。Linux操作系统实现同步机制的方法有信号量(semaphore)和互斥量(mutex),这两种方法相似,但各有侧重。信号量侧重于一个线程被另一个线程激活,常有先后执行的关系。而互斥量则保护某一共享内存任一时刻只有一个线程访问。网络通信线程和数据采集与存储线程之间的同步通过信号量来实现。
为了防止系统资源泄漏,保持各个线程的同步,主线程需要初始化数据采集驱动代码,为数据采集做好准备;申请相应的内存空间,用于存放采集到的实时数据;定义好各个信号量和互斥量。
4. 3线程的实现方法
数据采集与存储线程是获取数据的起始线程,由GU I线程创建,网络通信线程和决策线程是由数据采集与存储线程激活。下位机开始运行后,数据采集与存储线程启动,每隔5 s运行1次,读DI、AI接口的状态,并把这些状态和此刻的时间存入SQ Lite数据库中。数据采集与存储线程每运行一次,对信号量sem_decise和sem_ com进行一次post操作,分别激活决策线程和网络通信线程。数据采集与存储线程的同步流程如图4所示。
图4数据采集与存储线程的同步流程
数据采集与存储线程作为系统的数据源头,它激活了其它2个子线程,与之相对应,被激活的子线程随着它的结束而结束。线程在未接受到信号量激活时处于阻塞状态,不占用系统资源。前台处理用户界面的GUI线程与后台的工作线程之间是独立的。GU I线程提供友好的人机界面,它把被监控对象的信息实时显示在图形界面上,供现场工作人员查询和设置。
监控程序的每个线程都需要对存放被监控对象实时状态的数据缓冲区进行访问。由于Linux操作系统允许多个线程同时对某一数据缓冲区进行读操作,但在同一时刻对该数据缓冲区只能有一个写操作。GUI线程需要定时刷屏,更新被监控对象的实时状态,因而需要定时对缓冲区进行读操作,而数据采集与存储线程定时地对该缓冲区进行写操作,它们之间没有触发关系,是相互独立运行的。因此,需要对缓冲区设置一个互斥量,确保任一时刻这两个线程只有一个能对其进行访问。
数据采集与存储线程对缓冲区进行写操作之前,先对互斥量进行加锁操作,把实时状态写入数据缓冲区后,再进行解锁。这样避免了因与GU I线程争夺资源而造成系统不稳定的现象。上锁与解锁操作代码如下:
void * thr ead_collect ion(void * arg)
{
……
pthread_mu tex_lock(dat a_mu tex); / /上锁操作
read(fd, dat a, s izeof(dat a)); / /写实时状态到data缓冲区
pthread_mu tex_unl ock(dat a_m ut ex); / /解锁操作
/ /激活网络通信线程、决策线程,并写数据到数据库
……
}
同样,GUI线程中也需要对缓冲区进行相应的上锁、解锁操作。
网络通信线程和决策线程由GUI线程创建,由数据采集与存储线程激活,都是每5 s运行1次。
由于GPRS模块通过串口与下位机相连,并采用透明传输模式,即有数据即传输,因此,网络通信线程只需要定时对串口写操作就可以完成数据传输任务。网络通信线程先打开串口,设置串口的波特率、数据位、校验位等属性,然后等待数据采集与存储线程的信号量将其激活,第一次被激活后,进入了一个w hile循环,执行一次串口写操作,再等待下一次被激活。网络通信线程被激活的条件是数据采集与存储线程对信号进行了一次加1操作,即sem_ post(sem_2)。网络通信线程的关键代码如下:
fd= open(“/ dev/ t t ySC4”, O_RDWR);
set_sp eed(fd, 9 600); / /设置波特率
set_parit y(fd, 8, 1, %n); / /设置数据位、奇偶校验位
sem_w ait(s em_2); / /等待信号量激活
w h ile(1){
w rit e(fd, buf , sizeof(buf)); / /对串口写操作,发送数据
sem_w ait(sem_2); / /等待下一次信号量激活
}
pth read_exit(“thread exit \ n”); / /线程退出
决策线程的任务是对当前被监控对象的状态进行判断,如果有异常发生,则产生一个报警信号,并执行相关动作来应对这些异常。其代码结构与网络通信线程相似。
5结语
基于多线程的环境监控系统采用多线程技术完成下位机的多个任务,相对于单任务应用程序,多线程应用程序能够减少定时器的使用,节约系统资源,从而提高系统效率。而且,多线程应用程序更能体现模块化设计思想,程序易于维护和修改。该系统已经成功应用于多个项目之中,性能稳定可靠。