wpf探秘之B哥Dispatcher私房菜(1)
来源:互联网 发布:淘宝大数据平台架构 编辑:程序博客网 时间:2024/06/03 12:59
一切从我们熟悉的windows系统说起,话说windows系统,有一个概念是大家都不会陌生的,那就是消息循环,我们先来看看传统的win32是如何完成消息循环的,用C写过窗体程序的伙伴估计都会比较熟悉,消息循环在本质上就是一个大大的while循环,然后主线程里面创建消息队列,然后不断从消息队列中提取消息,进行消息的分发,我们再来回顾下当年用C++在没有mfc条件下的生活吧:
while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int) msg.wParam;}
消息总有的东西来标识吧,好吧,win32又搞出了一个handle(就是我们常说的句柄),msg中有一个句柄的字段,用来干什么呢,我们会在窗体注册时写一个回调函数,这个函数叫做窗体过程函数,一般的原型是这个样子的:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
用于当消息被处理时调用这个函数进行处理,handle就是区分消息的重要字段,当然也可以在消息中定义你自己的一个标识字段。
ok,说了这么多的win32,我们再来wpf给我们带来了什么,wpf本质上也是对win32进行了包装,穿上个华丽外衣,那么wpf中使怎么处理线程中的消息循环呢,我们免不了要引出dispatcher这个类,Dispatcher,顾名思义就是一个专门负责对消息进行派发的对象,但这个类是比较羞涩的,就连构造函数都要弄成private,所以很遗憾,我们并不能自己主动构造一个Dispatcher对象,但系统里面会有一个Dispatcher的静态对象,里面含有所有线程的Dispatcher的一个List,我们只能调用CurrentDispatcher来获得当前线程的一个Dispatcher,说到这个对象,熟悉android的伙伴肯定会情不自禁的想起android系统中一个类似的处理消息循环的对象,就是Looper,这同样也是一个羞涩的家伙,构造方法也不是公有的,同样,这两个对象都十分傲娇,只能保证每一线程有且仅有一个自己,不能花心。
Dispatcher要处理消息循环,就得像win32一样,有一个自己的消息泵,消息队列,以及消息处理机制,我们小赖看看它的消息泵是怎么搞的,先来一段代码:
while (frame.Continue) { if (!GetMessage(ref msg, IntPtr.Zero, 0, 0)) break; TranslateAndDispatchMessage(ref msg); }
比较它的消息泵实现,大家就会发现其实跟win32的消息泵也没什么两样吧,好,暂时先放下这个,我们再来看看它的消息队列是怎么回事,Dispatcher中的消息其实还是基于win32的消息队列的,只是在上面做了一层封装,先有一个叫做DO(Dispatcher Operation)的一个对象,这个东西封装我们定义的一个有一个的任务,丢给系统给我们处理的任务(这个东西跟我以前的写过的那个线程池任务队列机制有异曲同工之妙),我们不妨来看看DO在wpf中使怎样定义的:
public sealed class DispatcherOperation { public Dispatcher Dispatcher { get; } public DispatcherPriority Priority { get; set; } public object Result { get; } public DispatcherOperationStatus Status { get; } public event EventHandler Aborted; public event EventHandler Completed; public bool Abort(); public DispatcherOperationStatus Wait(); public DispatcherOperationStatus Wait(TimeSpan timeout); }
首先得有一个自己所在的那个Dispatcher的一个引用,然后就会出现一个这个do的优先级了,优先级是一个枚举类型,其中最高的优先级是send级别,基本这个级别的do是可以开辟绿色通道免排队等候的,消息一触发就马上执行,当然我们自己定义的修改UI的操作是可以定义为send级别的(我就经常这么干),至于其他的字段,都是以属性的形式暴露了结果(Result )啊,状态啊(Status )之类的,还定义了一些比如Aborted,Completed等事件,关于Dispatcher估计大家可能会以为既然每个线程都有一个,会不会就是在存在线程的本地空间中呢,其实Dispatcher是一个全局的线程共享对象,关于线程的同步死锁的机制在这里是适用的,在全局对象中,Dispatcher是一个包含所有线程Dispatcher的List集合,当当前线程请求获得Dispatcher对象或者是当需要跨线程调用时,就需要向这个列表提出获取Dispatcher的请求,然后List机会检测Thread的context,只有是属于线程才能发起对Dispatcher的获取,检测之后就开始在List中发起一轮新的List的遍历,遍历每一个Dispatcher的Thread的特征(主要是Tid),知道找到跟请求线程特征符合的Dispatcher,返回给当前请求的线程,这样就可以完成关于线程的本地调用以及跨线程调用,这种直接搞个内存共享区的好处就是如果给每个线程都分配一个线程本地存储空间(TLS)对于内存来说是一笔非常的的开销,所以咯,对于系统机制来说,当然是怎么节约怎么来咯,ok,现在我们就大概了解消息队列就是通过一个DO的队列来进行处理的(我称之为DO Queue),至于DO是如何被创建,以及DO从Queue中被处理的一些机制,这些比较复杂,我准备把它们留到下一篇文章再进行详细的分析,且看下回分解。。。。。
- wpf探秘之B哥Dispatcher私房菜(1)
- wpf探秘之B哥Dispatcher私房菜(2)最终回
- WPF私房菜之Brush画刷
- 深入WPF -- Dispatcher(补)
- WPF- Dispatcher
- WPF-Dispatcher
- linux鸟哥私房菜(1)
- shell--鸟哥私房菜(1)
- WPF multi-thread - Dispatcher WPF多线程 - Dispatcher
- 学习鸟哥私房菜(一)之 man page
- 学习鸟哥私房菜(七)之 shell scripts
- 《鸟哥的linux私房菜 基础篇》附录B(EXT2/EXT3文件系统)读书笔记
- 关于WPF Dispatcher
- WPF BackgroundWorker vs. Dispatcher
- 聊聊WPF中的Dispatcher
- WPF 线程 Dispatcher
- 鸟哥私房菜1
- 鸟哥的Linux私房菜之认识Bash Shell(1)
- HDU1166敌兵布阵
- 比较实用的注册表实用工具
- Android沉浸式状态栏实现
- hihocoder 1223 : 不等式(最大团问题)
- Secret
- wpf探秘之B哥Dispatcher私房菜(1)
- Android:TextView超出部分自动添加省略号
- paypal nvp name value paire paypal ecshop sanbox测试账号
- 【Window下apache服务设置最大连接数】
- ORA-01654 错误
- hdu5438 连通子图
- 黑马程序员---浅析 宏
- HDU1754 I 单点更新,区间最值
- php 计算3公里内所以用户的距离