简介
作为NET家族的一名新成员Net Micro Framework是微软专门针对超轻量级平台(主要是一些低端的位微处理器)设计的软件架构其结构如图
)thiswidth=; height=>
图 Net Micro Framework 架构
Net Micro Framework有且仅有一条本地执行线程这条线程上跑的就是Net Micro Framework CLR(TinyCLR)TinyCLR是一个可以自己引导的运行环境和完整版本的Net一样会管理它自己涉及的内存所以可以认为Net Micro Framework不需要依赖操作系统提供线程和内存管理的服务所以完全可以把Net Micro Framework移植到没有OS甚至没有内存管理单元(MMU)的某些arm处理器上
尽管只在单一的线程上执行但是CLR要求对驱动的调用看起来是异步的也就是说这些调用会立即返回而不是一直阻塞直到该任务的硬件I/O完成这和Windows下的APC(asynchronous procedure call)的实现非常类似TinyCLR的线程调度依赖于APC的完成模式APC的实现依赖于图中PAL层的定时器(Timer)的实现如图
image onmousewheel=javascript:return big(this) border= alt=Net Micro Framework上的异步调用 src=http://imgeducitycn/img_///jpg width= onload=javascript:if(thiswidth>)thiswidth=; height=>
图 Net Micro Framework上的异步调用
Micro Framework的基本线程操作
下面先简单介绍几种最基本的在Net Micro Framework被支持的线程相关方法
Join
和完整版的Net Framework一样Micro Framework的SystemThreadingThread类提供了Join方法所谓join(合并)用于使当前线程等待直至调用该线程的方法执行完毕或者到达指定的等待时间这里不做多的介绍了
Timer
这里是说SystemThreadingTimer类和完整版的Net Framework一样它的构造函数中提供了一个TimerCallback委托类型的参数它告诉线程池要拿出一个线程来按特定的时间或者频率执行这个callback函数
Event
Micro Framework中线程可以用事件的方式来响应 比如在访问一些共享资源的时候可以使用AutoResetEvent 通过WaitSet的组合来同步线程
以上几种基本操作在SDK的Threading例程中都有使用这里不再赘述
WPF与Dispatcher
初次接触Net Micro Framework那WPF风格的UI编程模型时(没有Windows Forms)总是面临着许多性能和安全上的问题其中很常见的就是数据更新和界面刷新的问题
典型的有UI的Micro Framework应用程序都会有两个逻辑线程一个是开发者显式创建用来处理硬件I/O的另一个是由TinyCLR隐式创建并维护的它用来处理所有的UI操作我们姑且把it叫做WPF UI线程例如绘制UI元素绘制控件和窗体等
Micro Framework中的UI元素的更新可以使用Dispacther和DispatcherTimer以线程安全的方式访问UI元素什么是Dispacther呢?你可以把它看作绑定在上述第二个线程上的一个消息队列WPF UI线程一直盯着这个队列来接受各种操作命令你只需要把你的命令即相关待执行的函数enqueue到这个队列即可让这个函数获得线程安全的执行
下面我们通过一个时钟的例子来说明如何在Micro Framework中使用Dispatcher在本例中我们会在一条单独的线程上更新画面上的文本打开Visual Studio创建一个Micro Framework的windows程序
首先在main函数之外我们定义一个文本和负责更新它的线程
private Text text; private Thread updateThread;
然后我们需要为这个更新操作定义一个委托这个委托的实例将被用来添加到WPF UI的消息队列中去
///
/// 用来更新文本的委托 ///
/// 新文本 public delegate void UpdateTextDelegate(String newText)
然后我们需要一个该委托的实例指向的实际函数它非常简单
public void UpdateText(String newText)
{
textTextContent = newText;
}
接下来我们还需要让UpdateThread做点什么就是要它通过Dispatcher来完成这个异步的线程安全的UI更新
public void UpdateTextThread()
{
while (true)
{
thisDispatcherBeginInvoke(new UpdateTextDelegate(UpdateText)
new object[] { DateTimeNowToString(hh:mm:ss) })
// 休眠秒
ThreadSleep()
}
}
最后我们要在CreatWindow方法返回前添加如下代码以启动上述线程
updateThread = new Thread(new ThreadStart(UpdateTextThread))
updateThreadStart()
其运行效果如下
image onmousewheel=javascript:return big(this) border= alt=运行效果 src=http://imgeducitycn/img_///jpg width= onload=javascript:if(thiswidth>)thiswidth=; height=>
这种有周期的调用方式还可以使用DispatcherTimer来处理此时唯一需要改变的是UpdateText的签名使之符合EventHander的格式
public void UpdateText(object sender EventArgs e) {
textTextContent = DateTimeNowToString(hh:mm:ss) }
使用DispatcherTimer非常简单
dispatchTimer = new DispatcherTimer(textViewDispatcher)
dispatchTimerTick += new EventHandler(UpdateText)
dispatchTimerInterval = new TimeSpan( )
dispatchTimerStart()
Micro Framework并不胜任所有情况
对于一些高吞吐量且对实时性要求比较高的情景(比如一个需要对音频数据流编解码输出CD音质的设备)使用Micro Framework设备做这些工作并不是一个好的选择要满足这样的需求你可以使用一些辅助的处理器(比如DSP)通过SPI或者IC连接到Micro Framework设备让它们去做繁重的数据处理工作而使用Micro Framework来创建友好的UI并承担一些非严格实时性的工作
另外一种方式就是把Micro Framework移植到一个多线程实时操作系统上然后把那些实时性高的代码交给一条高优先级的线程去跑
总结
NET Micro Framework 将 NET 的可靠性和效率与 Visual Studio的高生产率结合起来以针对价格较低资源受限的小型设备开发应用程序可帮助人们使用熟悉的 Visual Studio 工具来构建托管的嵌入式应用程序从中你可以发现使用托管代码以OO的方式在嵌入式设备上面编写拥有漂亮的UI的多线程程序是如此简单自然也许你再也不想回到过去那Win或者POSIX风格的代码中去了同时要注意Micro Framework的适用范围注意避免由MF直接承担一些实时性较高的大数据量的任务