APP下载

基于现代并发技术的测控系统软件设计

2018-11-05王越夏京川祁正兴陆小龙

机械制造与自动化 2018年5期
关键词:内核线程测控

王越,夏京川,祁正兴,陆小龙

(四川大学 制造科学与工程学院,四川 成都 610065)

0 引言

测控系统软件设计质量直接影响着测控系统稳定运行。其中,多个方面的因素决定了并发编程在现代测控系统软件中的必要性:1) 数据采集量大,并需要进行复杂算法处理,要求系统具有一定的可靠性、稳定性和实时性;2) 系统复杂度与集成度的不断提高增加了用户与应用程序交互的频率,要求软件具有良好的响应能力;3) 现代测控系统网络化发展趋势以及云计算的需求,软件中信息的传输速率需要进一步提高[1-2]。本文描述了利用Windows系统.Net Framework中的并发技术来设计测控系统软件,增强系统的整体性能。

1 并发编程技术简介

1.1 早期多线程技术

Windows系统中并发编程通常采用多线程模式,线程是运行在一个单一进程上下文中的逻辑流,由内核进行调度,其共享所在进程的整个虚拟地址空间。每一个线程都包括线程内核对象、线程环境块、用户模式栈、内核模式栈等内容[3]。进程在创建或终止任一线程时,会调用进程中加载的所有非托管DLL(dynamic linking library,动态链接库)的DllMain方法。

使用Thread编程模型,开发者能够直接创建与操纵操作系统级别的线程[1]。然而,线程的每一次创建、终止过程都会产生巨大的开销;同时,一个CPU任一时刻只能运行一个线程,过多的线程会导致频繁的线程上下文切换,造成更为严重的性能损耗。通常程序开发者无法了解计算机运行时特性,一味地增加线程必然会导致计算机资源的极大浪费。

Thread Pool模型则将线程管理工作移交到了操作系统本身,采取复用的方式(工作项在线程中排队,线程池线程执行完当前工作项后,继续执行下一个工作项)来确保计算机中线程数量维持在一个合理的值。Thread Pool使用特定的探索方式来决定是否添加新的线程,以及保证线程池中最大线程数量。在较新的Net版本(4.0及以上)中,线程数量最大值由可利用内存空间决定,这能充分利用现代计算机的多核CPU硬件资源[4]。

1.2 任务与异步

TPL(task parallel library,任务并行库)是基于Thread Pool工作原理提出的一种新的并发编程模型,其提供了一个规范、更易理解的并发编程结构。

Task是一种抽象概念,代表并发工作的基本单元,即是指被创建活动运行的同时,主(创建)线程仍然在持续执行[5]。Task可指定为工作线程或I/O线程,由Thread Pool进行调度,内置为后台线程执行并且不可改变。通过配置TaskCreationOptions与TaskScheduler选项可调整运行时Task参数,以适应不同的工作需求。

异步的核心理念是异步操作,启动了的操作将会在一段时间后完成,该操作不会阻塞原来的线程,其结束时会通知原有线程操作已完成[6]。编译器后台采用FSM(有限状态机)原理,实现future模式或回调机制,以避免产生不必要的线程。实现异步的通用方式为创建一个Task并指定ContinueWith()方法,通过配置同步上下文(SynchronizationContext),可将完成后的延续任务(continuation)调回到原有线程中执行。现代的异步.Net程序则主要使用两个关键字:async和await(.Net 4.5及以上)以简化异步操作的调用。

1.3 数据访问与同步

同一进程的多个线程将共享绝大多数运行资源与数据。当多个线程想同时获得同一个资源时,将产生竞争;当多段并发代码想同时访问一个数据,并且至少有一段代码在修改数据时,数据将变得不安全或产生错误。在以上两种情况下,都需要使用同步技术来协调多线程的执行,保证线程间的调用安全。

Windows提供了用户与内核模式构造线程同步机制。用户模式使用特殊CPU指令来协调线程,以确保数据变量呈现为原子性;而内核模式由Windows自身提供,可根据线程运行情况切换至等待、就绪、休眠等状态,有利于系统监测与整体管理[2]。为在实现系统可进行整体管理的同时最大化优化线程同步性能,更合理的方式是混合使用用户模式与内核模式,其实现形式包括Monitor、Lock、ManualResetEventSlim、ReaderWriterLockSlim等。

1.4 线程停止与任务取消

当程序并发运行时,用户常常因为某些原因中止并发线程。早期技术如Abort()方法将强制退出线程,可能使进程中共享资源处于无效状态而导致后续的错误,Interrupt()方法仅在线程处于WaitSleepJoin状态下完成,该状态由于线程原因可能永远无法达到从而造成死锁。在.Net 4.0中,提供CancellationTokenSource与CancellationToken来处理取消问题。其实现机制主要为协调取消请求与并发操作,在操作内部定义可安全取消位置,仅当程序运行在安全位置(通常采用轮询方式)时抛出异常并取消线程。

2 并发技术在测控系统软件中的应用

由上述可见,多线程的主要优势在于构建性能良好、可伸缩、响应灵敏的应用程序。其核心理念在于将线程与任务分开,线程由框架根据操作系统特性创建并维护,开发者仅需要创建可划分为小块的任务,框架将自动地将任务调度到合适的线程并执行。

为实现以上目标,关键在于两点:1) 不手动创建额外的线程;2) 已创建的线程不应该被阻塞以便更好地复用。

2.1 系统体系结构

在某测控系统设计中,程序应用划分为多个模块,其硬件结构与软件框架如图1所示。

图1 系统体系结构图

图中每个实线矩形框表示一个软件模块和功能。为达到最佳应用效果,各软件模块通常需要同时工作,程序应运行在多线程模式。本文以下内容将着重介绍各个模块并发状态下的应用技术与实现方法。

2.2 数据采集模块

数据对于测控系统至关重要。通常而言,被测物理量(信号)通过传感器采集,并在采集设备中对信号进行处理(硬件滤波、数模转换等);计算机通过软件驱动采集设备,获取信号进行再次加工(如软件滤波、数值转换),得到控制信号后输出到执行机构或视图界面,完成对系统的控制或展现给用户。

为保证控制系统的有效可靠,必然要求采集模块具有较高的实时性和稳定性。通过任务和异步,能够保证计算机在调度采集设备的同时,并行执行其他的业务逻辑。

首先,对采集设备API进行包装,如:

public class SomeDevice {

SemaphoreSlim slim=new SemaphoreSlim(1,1);

public async Task> GetAcquisitionAsync(object c){

return await Task.Run( async () => {

...

await slim.WaitAsync();

...//读取数据

slim.Release();

return datas;//返回数据

});

}

}

代码中使用了SemaphoreSlim类型的一个信号量对象来实现资源同步,这是目前.Net平台中唯一支持异步访问的同步构造。当SemaphoreSlim最大计数为1时,可对其保护的资源进行互斥访问。在应用程序的其他业务中,使用如下方式来得到采集数据:

vardevice = new SomeDevice();

var datas = await device.GetAcquisitionAsync(null);

当程序主线程执行方法遇到await关键字后,会启动另一个线程池线程执行await后所带的异步方法,而主线程无需阻塞,直接返回以执行其它工作。当异步方法结束,若之后还有操作,将会被包装为一个Task返回至主线程的任务队列,并通知主线程尽快执行,主线程会在合适的时间对后续Task进行调度。

2.3 I/O操作模块

目前大多数的计算机与IO设备都能够通过DMA(direct memory access,直接内存存取)的方式来进行数据传输,此时不需要消耗CPU资源,硬件会自动进行读写数据并与内存交换[7]。然而,若使用同步I/O,CPU通知硬件设备后,线程将会阻塞,直到硬件设备完成I/O操作,Windows再唤醒线程调度给CPU继续执行。在这个过程中线程处于休眠状态,若程序想完成其他工作,需要创建新的线程。当休眠状态被唤醒后,因为加入了新线程,运行线程数量可能已超过最合适的值,计算机将会执行的线程时间片切换,造成巨大的性能损耗。

使用异步操作可避免以上情况。在.Net常用的IO操作,如文件读取、写入,Stream的应用,数据库Command的执行中,有些已经提供了异步方法,有些则提供了早期版本的BeginXxx/EndXxx方法与IAsyncResult接口,需要使用以下方式进行包装:

var io = new IODevice(...);

await Task.Factory.FromAsync(io.BeginXxx, io.EndXxx);

对于未提供异步方法的IO操作,可手动进行包装。以下代码提供了序列化操作的异步接口与序列化到xml文件的实现:

public interface IAsyncSerializer{ Task WriteAsync(string path, T obj);}

public class XmlSerializer : IAsyncSerializer{

...

public async Task WriteAsync(string path, T obj){

return await Task.Run(()=>{

using(var stream = File.Open(path, FileMode.OpenOrCreate)){

var serializer = new XmlSerializer(obj.GetType());

serializer.Serialize(stream, obj);

}

});

}

}

2.4 UI操作与业务逻辑

随着测控系统软件综合化程度的提高,与操作者的交互频率也将不可避免地增加。通常GUI框架(如MFC、WinForm、WPF等)的控件与创建者线程具有“线程相关性”,其他线程永远无法直接访问用户界面控件,这为基于多线程的GUI应用程序带来了困扰。通过异步的方式能够解决该问题,并进一步提高程序的响应能力。

可直接将异步操作注册到控件(如Button)的事件中,如:

CancellationTokenSource ctSource;

private async void ButtonStartClick(object sender, EventArgs e){

var model = new Experiment();

this.textBox.Text = await model.Execute(ctSource.Token);

}

private void ButtonStopClick(object sender, EventArgs e){

ctSource.Cancel();

}

在代码中,Execute是一个返回Task的异步方法,它将在另一个线程池线程中执行。执行结束后,它将返回调用者线程(在此处是UI线程)继续后面的工作,即textBox控件Text属性的赋值过程在UI线程中执行。同时,注意代码中Text的新值被声明为Execute的返回值,从而使得UI与线程池线程不再共享数据,起到可变量隔离作用,以避免执行复杂的数据同步过程和带来的性能损失。

并且异步调用在Execute执行的同时,UI线程能够响应用户的其他操作,不至于卡顿。此外,代码在UI线程中声明了CancellationTokenSource对象,它的Token属性将被传到Execute方法中。若Execute是一个费时的操作,用户可操作CancellationTokenSource(如这里的点击Stop按钮)取消Execute的执行。任务将在一个安全的、可控制的位置停止,这是开发者可以操控的。此时Execute大致的结构将如下:

public async Task Execute(CancellationToken token){

return await Task.Run(()=>{

int totalTimes=10000;

for(int times = 0;times

...//其他操作

token.ThrowIfCancellationRequest();//抛出异常以停止

}

return "Completed";

},token);

}

2.5 数据处理

测控系统通常包含大量的数据处理,包括滤波、数值转换、计算结果、图形图像处理等。这些过程通常为CPU密集型操作,创建多于CPU内核数的线程将严重影响计算机性能。使用TPL中Parallel的For、ForEach方法,开发者将复杂的线程调度过程委托给操作系统执行,能够更关注于应用逻辑并提升并行性能。

IEnumerable datas = await acquirer.GetAcquisitionAsync();

object lockObject = new object();

double result = 0;

Parallel.ForEach(data, () => 0, (item, state, returnValue) => ExecuteCompute(item), returnValue =>{Monitor.Enter(lockObject);

result += returnValue;

Monitor.Exit(lockObject);

});

以上代码对集合datas中的每一项都进行ExecuteCompute运算,再将运算结果统计至局部变量result中。其中,每一小块都被划分为一个任务,被动态分配到空闲线程的任务队列中以并行方式执行,而操作系统则会根据硬件特性委派给不同的CPU,并根据当前任务与线程数量决定是否增加新的线程。

任何一项任务完成后,将会继续执行求和操作,涉及到的result是一个共享变量,需要进行同步。此处使用Monitor构造能得到较好性能。

3 结语

本文利用.Net Framework下的现代并发编程API,实现了某测控系统中软件重要模块的编写。其中,异步方式有利于构建IO设备模块和实现反应迅速的GUI交互界面;而并行则适用于需要CPU执行的计算密集性操作,以保证充分利用当代多核多处理器的硬件性能。以上技术的实现为构造一个性能良好、可伸缩、响应灵敏的应用程序奠定了坚实的基础。

猜你喜欢

内核线程测控
多内核操作系统综述①
强化『高新』内核 打造农业『硅谷』
基于C#线程实验探究
活化非遗文化 承启设计内核
昆山祺迈测控设备有限公司
基于国产化环境的线程池模型研究与实现
线程池调度对服务器性能影响的研究*
Linux内核mmap保护机制研究
基于现代测控技术及其应用分析
虚拟仪器技术在农业装备测控中的应用