Winform消息与并行的形象比喻
有一次我给同事讲述跨线程调用时使用了高速行驶的并行列车来比喻,感觉比较形象。
线程列车
多线程就像多个并行的列车,每个线程在各自的轨道上不断向前行驶。主界面所在的线程称为UI线程,也叫主线程,主线程依靠消息驱动,可以将主线程的列车每节车厢想象为一个消息,每次转换并处理一个消息,处理过程中如果有新的消息不会马上处理而是放入一个消息队列,等下一轮处理。
例如我在屏幕上点击一个按钮,操作系统将鼠标的按下抬起等消息推送到消息队列中。程序主线程的下一轮开始转换这个消息然后处理这个消息,发送给指定窗口。假设我们在点击消息处理方法中进行一些界面更新,并调用了Invalidate,此时只是发出了消息,然后继续执行后续代码,当点击消息处理完毕后,才会从消息队列获取下一个消息处理。
对于跨线程操作的Invoke,可以这么理解。就是并行列车在高速行驶中如果直接调用另一个列车上的方法是非常危险的,我们坐车的时候售票员总是提醒我们不要把头和手伸出窗外是一个道理。所以,假如我们在一个主线程之外的线程列车上想要UI线程去执行一个方法,此时我们需要将方法包装成委托,然后通过Control.Invoke给主线程发送消息,主线程会在下一次消息处理时处理我们的消息,由被调用的Control在UI线程执行我们的方法。
如果我们在Invoke后,还需要处理返回值,那么我们自己所在的列车就不能继续开了,要停下列车,等主线程的列车处理完我们的方法,返回结果,并通过消息发送回来,我们收到返回的消息时,才继续开动列车处理后续消息。也就是使用Invoke的返回的WaitHandle的WaitOne方法等待了。
需要理解Windows的消息驱动机制。我们知道任意时刻执行的代码一定是处于一个消息中,或者是空闲事件消息中。消息也是跨线程调用的基本机制。
Control.BeginInvoke是从线程池启动一个线程执行,相对主线程是异步的。Control.Invoke则是在其他线程中回到UI线程执行。但这两种方式都不是推荐的最优做法,推荐用TPL模式,就是使用Task来进行异步。需要回到主线程时用AsyncOperation,原理是一样的还是发消息,只是AsyncOperation会发送给一个必定存在的句柄,避免线程安全问题。
句柄问题
另一个很多人不明白的问题就是窗口句柄何时创建,以及OnLoad的时机。其实,Winform程序是对本地代码的包装而已,底层还是过程式语言的API调用。过程语言通过句柄来唯一标识所有的本地资源,所有的方法都需要传入句柄 。而我们创建的控件类其实并不是真正的可见的类,翻看C++版本的代码就可以知道,其实还是调用API来CreateWindow,此时传入的类名才是API中所指的类名,此时传入的参数在Control里使用了CreateParam结构体和CreateParam方法来实现。
简单的说吧,当我们创建一个Button时,只是调用了Button的构造方法而已,并没有在屏幕上可见,当我们调用Parent的AddControl时,才会去创建句柄,此时才会触发控件的OnCreateControl,如果控件是一个UserControl才会触发OnLoad事件。Control的OnCreateControl和UserControl的OnLoad是同一个时机发生的。只有创建了句柄才会在屏幕上绘制出来,当父窗体隐藏时,所有子控件的句柄会销毁,因为不用绘制了,而再次Show时,会重新创建句柄。
Winform消息与并行的形象比喻的更多相关文章
- 加密解密(5)SSL形象比喻
转自: http://blog.csdn.net/cloverphp/article/details/11737433 前言: 关于公钥,私钥请看前几篇文章 SSL 协议既用到了公钥加密技术(握手 ...
- 大数据技术生态圈形象比喻(Hadoop、Hive、Spark 关系)
[摘要] 知乎上一篇很不错的科普文章,介绍大数据技术生态圈(Hadoop.Hive.Spark )的关系. 链接地址:https://www.zhihu.com/question/27974418 [ ...
- winform消息提示框
摘自:http://www.cnblogs.com/risen/archive/2008/01/15/1039751.html public partial class AlertForm : For ...
- ajax获取数据的形象比喻,助于理解记忆
过程 创建对象(打开浏览器) 连接服务器(输入网址) 发送请求(按下回车) 服务器接收并返回数据(显示对应的网址网站内容) 原理
- I/O存取方式的形象比喻
I/O存取有三种方式:可编程I/O.中断驱动I/O.DMA,分别可理解如下: 下面以老师向班里同学收发作业来类比I/O存取,办公室表示内存,即,I操作表示:老师向学生收作业,然后存放到办公室里:O操作 ...
- NIO与传统IO的区别(形象比喻)[转]
传统的socket IO中,需要为每个连接创建一个线程,当并发的连接数量非常巨大时,线程所占用的栈内存和CPU线程切换的开销将非常巨大.使用NIO,不再需要为每个线程创建单独的线程,可以用一个含有限数 ...
- BIO、NIO、AIO的形象比喻
BIO (Blocking I/O):同步阻塞I/O模式. NIO (New I/O):同步非阻塞模式. AIO (Asynchronous I/O):异步非阻塞I/O模型. 先看阻塞和非阻塞的区别, ...
- Windows服务调用Quartz.net 实现消息调度
Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用中.它提供了巨大的灵活性而不牺牲 ...
- C#.NET 消息机制
一.消息概述 众人周知,window系统是一个消息驱动的系统, windows操作系统本身有自己的消息队列,消息循环,它捕捉键盘,鼠标的动作生成消息,并将这个消息传给应用程序的消息队列. 余下的工作有 ...
随机推荐
- Android AVD启动报错:emulator: ERROR: x86_64 emulation currently requires hardware acceleration! Please ensure Intel HAXM is properly installed and usable.
打开Android SDK manager查看安装发现HAXM在windows上无法安装 可以去 http://www.androiddevtools.cn/index.html 下载 Android ...
- 全局API
Vue.extend( options ): extend创建的是一个组件构造器,而不是一个具体的组件实例 //选项对象 baseOptions let baseOptions= { template ...
- 转:Spring历史版本变迁和如今的生态帝国
Spring历史版本变迁和如今的生态帝国 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/bntX2jSQfEHy7/article/deta ...
- patindex
功能:返回模式在字符串中第一次出现的位置 解释:patindex('%pattern%',expression) pattern:要查找的模式 expression:被找的字符串 例子:select ...
- msdn原版系统和原版office
建议使用迅雷下载工具进行下载 激活详见:在线激活win10.win8/8.1和office2019.2016.2013等的kms激活工具 windows 10 家庭版/家庭单语言版/专业版/教育版/专 ...
- 【python系列】--Python变量和数据类型
python数据类型 一.整数 Python可以处理任意大小的整数,当然包括负整数,在Python程序中,整数的表示方法和数学上的写法一模一样,例如:1,100,-8080,0,等等. 计算机由于使用 ...
- h1-h3使用
一个页面也就只允许出现一个h1标签.内容页文章的标题,是seo中使用最多的地方,基本的文章页面标题都是使用h1标签.一.<h1>用来修饰网页的主标题,一般是网页的标题 ,文章标题,< ...
- C#接口的简单创建及其用法
我初次接触接口(Interface),对接口的作用有点迷茫,C#接口中包含方法.属性.索引器和事件的声明,但常用的接口中一般就是方法和属性,然而接口中并没有方法的具体实现代码(不能提供任何成员实现), ...
- JS学习过程中碰到的小问题
使用循环语句查找通讯录 //Setup var contacts = [ { "firstName": "Akira", "lastName" ...
- 三丶JavaScript 的基础学习(一)
知识预览 BOM对象 DOM对象(DHTML) 8 实例练习 JavaScript概述 JavaScript的历史 1992年Nombas开发出C-minus-minus(C--)的嵌入式脚本语言 ...