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中被处理的一些机制,这些比较复杂,我准备把它们留到下一篇文章再进行详细的分析,且看下回分解。。。。。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 华娱,我的老婆我自己捧 全民投资:开局我选悟空 求你们了,让朕当个昏君吧 凌队的千面保镖超A的 我不只是动作巨星 穿越三国:这个阿斗不用扶 绑定百亿物资系统后暴富古代了 遮天之凡体至尊 穿越诸天神话 重生79之我在美国开银行 首次穿越撞上氢弹是否搞错了什么 港综世界的警察 满朝奸臣,你让朕怎么当千古一帝 我的火种战舰 我在魔王城伪装怪物 女配在年代文里做万人迷 九品仙路 护林日常:开局拯救大熊猫 穿越兽世:种田驭夫乐悠悠 不灭战神 我在宝可梦世界开餐厅 爸爸,我是来当你同学的 这个主角明明很强却异常谨慎 四合院:我的穿越为啥这么陋 甩了线上男友后我被亲哭了 人在南天坐看万古 为了成为英灵我只好在历史里搞事 我成了游戏里的反派之王 离婚后,前夫每天都想上位 霍格沃茨的风与鹰翼 攻略暴君后,我抱错大腿了 我的精灵模拟器 金鸾喜嫁 人在美漫,开局枪斗术 大国科技从手机开始 人住超神,渣在诸天 斗罗之王者吕布降临 从白蛇开始诸天改命 诸天之天外降临者 屠龙之前就读过龙族的路明非 足球盛宴,从收购欧洲俱乐部开始