- 浏览: 462760 次
- 性别:
- 来自: 坚持零分
文章分类
最新评论
-
wzwahl36:
文章非常赞,http://www.atool.org/img2 ...
在浏览器中解析Base64编码图像 -
realyasswl:
ie sucks
IE9 媲美Firebug的强大的程序员开发工具 -
di1984HIT:
不错啊。呵呵。
MS的一些小工具 -
NothingCanBeDone:
楼主,你这Project,能放出来了,感激不尽。
[Ray Linn]用Visual Studio 2008开发IE BHO(浏览器帮助对象) 之三 -
烬难烬:
这就没了???我去....
IE9 媲美Firebug的强大的程序员开发工具
为什么需要SynchronizationContexts
“乌龟爬”这个奇怪的名字,因为在前面那个演示里,我试图用ironruby或者ironpython去控制一只小乌龟,(就是那个三角箭头),通过ironruby的命令让小乌龟前进、后退、左转、右转。
这里存在一个线程同步的问题,敲下一个命令之后,屏幕上的UI物件应该要马上按指令运作(体会一下魔兽世界的宏),所以小乌龟工作在一个UI线程里,而命令窗口工作在一个非UI的线程,如果不加任何处理的话,直接在命令窗口里操作UI物件的引用就会导致一个System.InvalidOperationException: “Object is currently in use elsewhere"(.net 2.0),或者得到一个不可知的状态(.net 1.0)。
应用场景和解决方案
上面提出的一个很常见问题:应用程序有两个线程:线程A和线程B,不过线程B比较特殊,它属于UI线程,当这两个线程同时运行的时候,线程A有个需求:"修改UI对象的属性",这时候如果你是线程A,你会如何去完成需求呢?!可能有几种解决方案。
第一种方式:
在线程A上面直接去操作UI对象,这是线程B说:"线程A,你不知道我的特殊嘛!",然后直接抛给线程A一个InvalidOperationException,线程A得到异常后,一脸的无辜和无奈.....!
第二种方式:
InvokeRequired?!是的,当然没问题。(InvokeRequired属性是每个Control对象都具有的属性,它会返回true和false,当是true的时候,表示它在另外一个线程上面,这是必须通过Invoke,BeginInvoke这些方法来调用更新UI对象的方法,当是false的时候,有两种情况,1:位于当前线程上面,可以通过直接去调用修改UI对象的方法,2:位于不同的线程上,不过控件或窗体的句柄不存在。对于句柄是否存在的判断,可以通过IsHandleCreated来获取,如果句柄不存在,是不能调用Invoke...这些方法的,这时候你必须等待句柄的创建。有点寒)
这些代码对还在使用.NET 1.0下的朋友还是有所帮助的:
在MyThreadClass类中就存在MyFormControl的引用对象。其实如果这个类放在这里是没有任务不妥之处的,但是如果把MyThreadClass类放在业务层,这时候问题就出现了,从设计角度来说,业务层是不允许和UI有任何关系,所以MyFormControl的引用对象绝对不能存在于MyThreadClass类,但是不让它存在,更新UI控件的需求就满足不了,这种情况下,我们如何做到一种最佳方案呢!?
这种场景就是SynchronizationContext大显身手的时刻。
第三种方案:
根据MSDN的介绍:SynchronizationContext 类是一个基类,可提供不带同步的自由线程上下文。 此类实现的同步模型的目的是使公共语言运行库内部的异步/同步操作能够针对不同的异步模型采取正确的行为。此模型还简化了托管应用程序为在不同的同步环境下正常工作而必须遵循的一些要求。同步模型的提供程序可以扩展此类并为这些方法提供自己的实现。
用大白话说,就是允许一个线程和另外一个线程进行通讯,SynchronizationContext在通讯中充当传输者的角色。另外这里有个地方需要清楚的,不是每个线程都附加SynchronizationContext这个对象,只有UI线程是一直拥有的,当Control对象被创建的同时,SynchronizationContext对象也会被创建并附加到UI线程上。
程序首先在Form1窗体的mToolStripButtonThreads_Click事件中,获取当前的SynchronizationContext对象,然后启动另外一个线程,并且将SynchronizationContext对象传递给启动的线程,启动的线程通过SynchronizationContext对象的Post方法来调用一个委托方法UpdateUI,因为UpdateUI是执行在主UI线程上的,所以可以通过它来修改UI上对象的信息。现在我们可以把Control引用给抛弃了。
Send VS Post,以及异常处理
首先看下异常处理的情况
当你运行的时候, 你可能希望在UI线程上面去抛出,但是结果往往出忽你的意料,异常信息都在Run方法的线程上被捕获了。这时候你可能想问:WHY?!
解释之前,我们先看下,Send VS Post的结果:
Send 方法启动一个同步请求以发送消息
Post 方法启动一个异步请求以发送消息。
哈哈,异常处理的答案迎韧而解了吧!
“乌龟爬”这个奇怪的名字,因为在前面那个演示里,我试图用ironruby或者ironpython去控制一只小乌龟,(就是那个三角箭头),通过ironruby的命令让小乌龟前进、后退、左转、右转。
这里存在一个线程同步的问题,敲下一个命令之后,屏幕上的UI物件应该要马上按指令运作(体会一下魔兽世界的宏),所以小乌龟工作在一个UI线程里,而命令窗口工作在一个非UI的线程,如果不加任何处理的话,直接在命令窗口里操作UI物件的引用就会导致一个System.InvalidOperationException: “Object is currently in use elsewhere"(.net 2.0),或者得到一个不可知的状态(.net 1.0)。
应用场景和解决方案
上面提出的一个很常见问题:应用程序有两个线程:线程A和线程B,不过线程B比较特殊,它属于UI线程,当这两个线程同时运行的时候,线程A有个需求:"修改UI对象的属性",这时候如果你是线程A,你会如何去完成需求呢?!可能有几种解决方案。
第一种方式:
在线程A上面直接去操作UI对象,这是线程B说:"线程A,你不知道我的特殊嘛!",然后直接抛给线程A一个InvalidOperationException,线程A得到异常后,一脸的无辜和无奈.....!
第二种方式:
InvokeRequired?!是的,当然没问题。(InvokeRequired属性是每个Control对象都具有的属性,它会返回true和false,当是true的时候,表示它在另外一个线程上面,这是必须通过Invoke,BeginInvoke这些方法来调用更新UI对象的方法,当是false的时候,有两种情况,1:位于当前线程上面,可以通过直接去调用修改UI对象的方法,2:位于不同的线程上,不过控件或窗体的句柄不存在。对于句柄是否存在的判断,可以通过IsHandleCreated来获取,如果句柄不存在,是不能调用Invoke...这些方法的,这时候你必须等待句柄的创建。有点寒)
这些代码对还在使用.NET 1.0下的朋友还是有所帮助的:
using System; using System.Drawing; using System.Windows.Forms; using System.Threading; public class MyFormControl : Form { public delegate void AddListItem(String myString); public AddListItem myDelegate; private Button myButton; private Thread myThread; private ListBox myListBox; public MyFormControl() { myButton = new Button(); myListBox = new ListBox(); ....控件初始化过程,略过.... myDelegate = new AddListItem(AddListItemMethod); } static void Main() { MyFormControl myForm = new MyFormControl(); myForm.ShowDialog(); } public void AddListItemMethod(String myString) { myListBox.Items.Add(myString); } private void Button_Click(object sender, EventArgs e) { myThread = new Thread(new ThreadStart(ThreadFunction)); myThread.Start(); } private void ThreadFunction() { MyThreadClass myThreadClassObject = new MyThreadClass(this); myThreadClassObject.Run(); } } public class MyThreadClass { MyFormControl myFormControl1; public MyThreadClass(MyFormControl myForm) { myFormControl1 = myForm; } String myString; public void Run() { for (int i = 1; i <= 5; i++) { myString = "Step number " + i.ToString() + " executed"; Thread.Sleep(400); // Execute the specified delegate on the thread that owns // 'myFormControl1' control's underlying window handle with // the specified list of arguments. myFormControl1.Invoke(myFormControl1.myDelegate, new Object[] {myString}); } } }
在MyThreadClass类中就存在MyFormControl的引用对象。其实如果这个类放在这里是没有任务不妥之处的,但是如果把MyThreadClass类放在业务层,这时候问题就出现了,从设计角度来说,业务层是不允许和UI有任何关系,所以MyFormControl的引用对象绝对不能存在于MyThreadClass类,但是不让它存在,更新UI控件的需求就满足不了,这种情况下,我们如何做到一种最佳方案呢!?
这种场景就是SynchronizationContext大显身手的时刻。
第三种方案:
根据MSDN的介绍:SynchronizationContext 类是一个基类,可提供不带同步的自由线程上下文。 此类实现的同步模型的目的是使公共语言运行库内部的异步/同步操作能够针对不同的异步模型采取正确的行为。此模型还简化了托管应用程序为在不同的同步环境下正常工作而必须遵循的一些要求。同步模型的提供程序可以扩展此类并为这些方法提供自己的实现。
用大白话说,就是允许一个线程和另外一个线程进行通讯,SynchronizationContext在通讯中充当传输者的角色。另外这里有个地方需要清楚的,不是每个线程都附加SynchronizationContext这个对象,只有UI线程是一直拥有的,当Control对象被创建的同时,SynchronizationContext对象也会被创建并附加到UI线程上。
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void mToolStripButtonThreads_Click(object sender, EventArgs e) { // let's see the thread id int id = Thread.CurrentThread.ManagedThreadId; Trace.WriteLine("mToolStripButtonThreads_Click thread: " + id); // grab the sync context associated to this // thread (the UI thread), and save it in uiContext // note that this context is set by the UI thread // during Form creation (outside of your control) // also note, that not every thread has a sync context attached to it. SynchronizationContext uiContext = SynchronizationContext.Current; // create a thread and associate it to the run method Thread thread = new Thread(Run); // start the thread, and pass it the UI context, // so this thread will be able to update the UI // from within the thread thread.Start(uiContext); } private void Run(object state) { // lets see the thread id int id = Thread.CurrentThread.ManagedThreadId; Trace.WriteLine("Run thread: " + id); // grab the context from the state SynchronizationContext uiContext = state as SynchronizationContext; for (int i = 0; i < 1000; i++) { // normally you would do some code here // to grab items from the database. or some long // computation Thread.Sleep(10); // use the ui context to execute the UpdateUI method, // this insure that the UpdateUI method will run on the UI thread. uiContext.Post(UpdateUI, "line " + i.ToString()); } } /// <summary> /// This method is executed on the main UI thread. /// </summary> private void UpdateUI(object state) { int id = Thread.CurrentThread.ManagedThreadId; Trace.WriteLine("UpdateUI thread:" + id); string text = state as string; mListBox.Items.Add(text); } }
程序首先在Form1窗体的mToolStripButtonThreads_Click事件中,获取当前的SynchronizationContext对象,然后启动另外一个线程,并且将SynchronizationContext对象传递给启动的线程,启动的线程通过SynchronizationContext对象的Post方法来调用一个委托方法UpdateUI,因为UpdateUI是执行在主UI线程上的,所以可以通过它来修改UI上对象的信息。现在我们可以把Control引用给抛弃了。
Send VS Post,以及异常处理
首先看下异常处理的情况
private void Run(object state) { // let's see the thread id int id = Thread.CurrentThread.ManagedThreadId; Trace.WriteLine("Run thread: " + id); // grab the context from the state SynchronizationContext uiContext = state as SynchronizationContext; for (int i = 0; i < 1000; i++) { Trace.WriteLine("Loop " + i.ToString()); // normally you would do some code here // to grab items from the database. or some long // computation Thread.Sleep(10); // use the ui context to execute the UpdateUI method, this insure that the // UpdateUI method will run on the UI thread. try { uiContext.Send(UpdateUI, "line " + i.ToString()); } catch (Exception e) { Trace.WriteLine(e.Message); } } } /// <summary> /// This method is executed on the main UI thread. /// </summary> private void UpdateUI(object state) { throw new Exception("Boom"); }
当你运行的时候, 你可能希望在UI线程上面去抛出,但是结果往往出忽你的意料,异常信息都在Run方法的线程上被捕获了。这时候你可能想问:WHY?!
解释之前,我们先看下,Send VS Post的结果:
Send 方法启动一个同步请求以发送消息
Post 方法启动一个异步请求以发送消息。
哈哈,异常处理的答案迎韧而解了吧!
发表评论
-
NET 4.0 多任务编程 之三 改进的线程池
2010-07-16 14:58 2228其实从.NET设计之初中就 ... -
NET 4.0 多任务编程 之四 Parallel初体验
2010-07-16 14:23 2165在.NET Framework 4.0中,在 ... -
.NET 4.0 多任务编程 之二 线程安全的集合
2010-07-14 13:54 3463随着多核计算机的普及 ... -
【C#】在C#中引用CygWin和MingW的Dll
2010-06-20 08:47 0在Windows上引入Unix或Linux的软件包,一般有以下 ... -
Java 7 闭包 -- 向C#学得更多
2010-06-08 10:55 210什么是闭包 简单来讲,闭包允许你将一些行为(包括语法和表达式 ... -
【Ray谈C#] MEF 扩展性管理框架
2010-05-28 16:58 3990原文发表于:blogs.ejb.cc M ... -
用DLR创建自己的语言之一
2010-01-04 14:35 2536原文刊登于: http://www.bitwisemag.co ... -
C# 语法书 之可选参数
2009-12-22 14:40 2936适用C#版本:4.0以后 首 ... -
C# 语法书 <3> 静态类,别名等等
2009-06-30 11:32 1759最近比较忙,所以先跳 ... -
初窥Nemerle语言
2009-06-23 14:23 1741Nemerle是Microsoft的研究项目之一,由 Wroc ... -
C# 语法书 <2> 委托 delegate
2009-06-15 16:40 1883为什么要有委托? 先 ... -
C# 语法书 之 <1> 迭代器
2009-06-09 16:42 1332这个系列的主要目的是尽量能覆盖C# 1.1之后的语法更新,以便 ... -
What's New in C# 4.0 之一 语法
2009-06-08 14:54 24011. dynamic简介 在之前的文章有简单的谈到dynam ... -
What's New in .net 4.0 - 基础类库
2009-06-01 10:34 11491. System.Numerics.BigInteger ... -
一切为了并行:MS Axum语言教程 <四>
2009-05-14 15:12 1214数据流网编程 在程序中,代理之间通过发送和接受消息彼此沟通, ... -
一切为了并行: MS Axum语言教程 <三>
2009-05-13 14:35 1416域与状态共享 消息传递是种优秀的沟通机制,但它要消息中的数据 ... -
一切为了并行:MS Axum语言教程 <二>
2009-05-12 15:12 1019代理编程 上面的斐波那契数列的例子只是展示了一个微不足道的构 ... -
一切为了并行:MS Axum语言教程 <一>
2009-05-12 10:47 1453原文和更新参见: Ray Li ... -
C# 4.0中的契约式编程
2009-04-24 11:19 2883一切从质量谈起 许多 ... -
C# 利用范型与扩展方法重构代码
2008-04-03 14:58 2611在一些C#代码中常常可以看到 //An Simple Ex ...
相关推荐
3dsmax插件V-Ray LUTs 资源管理器 v0.02V-Ray LUTs 资源管理器 v0.02V-Ray LUTs 资源管理器 v0.02V-Ray LUTs 资源管理器 v0.02V-Ray LUTs 资源管理器 v0.02V-Ray LUTs 资源管理器 v0.02V-Ray LUTs 资源管理器 v0.02V...
8. **POV-Ray语法**:虽然这个程序是用C#编写的,但可能参考了POV-Ray的语法,以便用户能编写类似于POV-Ray的场景描述文件,描述场景的布局和物体属性。 9. **优化策略**:光线追踪往往需要大量计算,因此,有效的...
"ray-mmd-master.zip" 是一个包含 "ray-mmd" 项目的压缩文件,该项目是一个用于三维模型动画渲染的开源工具,特别关注于MikuMikuDance (MMD) 文件格式的支持。MMD是一种流行的3D动画软件,主要用于创建虚拟偶像如...
西门子X射线管RAY14中文说明书提供了一系列关于RAY14型X射线管组件的详细信息,包括其设计、特性、技术数据和操作指南。西门子X射线管RAY14适用于普通和数字X射线摄影以及透视工作站的常规检查的诊断。 知识点1:X...
在C#环境中实现光线追踪,可以利用其强大的面向对象编程特性以及丰富的库支持,来创建复杂的视觉效果。 光线追踪的核心在于计算光线与场景中物体的交互。这个过程包括以下几个关键步骤: 1. **光线生成**:程序...
"ray-mmd-1.5.2.zip" 是一个压缩包文件,主要针对MMD(MikuMikuDance)的渲染技术。MMD是一款基于3D动画的免费软件,最初设计用于虚拟偶像初音未来及其相关角色的舞蹈和歌曲表演模拟。这个1.5.2版本的"ray-mmd"包含...
在C#编程中,判断一个点是否位于一个多边形区域内是一项常见的几何运算任务,尤其在地理信息系统(GIS)和地图应用中。这个任务通常应用于确定某个地理位置是否在特定的地理边界内,例如行政区划、建筑物轮廓等。在...
"ray-master.zip" 文件是一个压缩包,通常包含了一个名为 "ray-master" 的项目或软件的源代码仓库。Ray 是一个开源的、可扩展的实时计算系统,它在人工智能(AI)和大规模分布式应用中被广泛使用。这个压缩包可能是...
本文将深入探讨“ray filter”算法及其在PCL(Point Cloud Library)中的实现。 首先,了解“ray filter”算法的核心思想。该算法基于射线追踪原理,通过计算每个点到某一参考平面的距离来判断其是否为地面点。如果...
POV-Ray,全名是Persistence of Vision Raytracer,是一个使用光线跟踪绘制三维图像的开放源代码免费软件。
本项目以"C#将文本数据转换成语音进行播报实例"为主题,适用于.NET Framework 4.0环境,为开发者提供了一个完整的解决方案。 首先,我们要了解C#中实现TTS的核心库——System.Speech。这个库包含了...
Ray是开源的分布式计算框架,它提供了一种高效、灵活且易于使用的平台,用于构建大规模并行和异步应用程序。这个“ray-2.3.1-cp37-cp37m-win-amd64.whl”文件是Ray的一个Python wheels格式的发行版,适用于Python ...
《深入理解Ray Match灯光雾技术在mental ray渲染中的应用》 在三维图形渲染领域,mental ray作为一款强大的渲染引擎,提供了丰富的光照模型和特效技术,其中Ray Match灯光雾技术是其独特且高效的雾化效果解决方案。...
V-Ray是一款广受欢迎的渲染引擎,专为3D建模软件如3ds Max设计。2011年的版本,即“V-Ray 2011”,是该软件的一个重要里程碑,提供了许多先进的技术和功能,旨在提升3D图像的制作质量和效率。 首先,V-Ray的核心...
V-Ray 是一款强大的渲染引擎,尤其在3D建模和设计领域中被广泛使用。它为3ds Max等三维软件提供了高级的光照计算和图像渲染功能。V-Ray 64位版本是专为64位操作系统设计的,能够充分利用多核处理器的优势,处理更...
标题《Ray Tracing in One Weekend》和描述表明,这是一本关于光线追踪技术(ray tracing)的入门书籍,作者是Peter Shirley。作者分享了这本书,并说明读者可以在一个周末内学习基础的光线追踪技术。这本书被归类在...
V-Ray是一款广受欢迎的高质量渲染引擎,被广泛应用于建筑可视化、电影、电视和游戏制作等领域。这个特定的版本,V-Ray 2.0 SP1,是专为3ds Max 2009 64位设计的,它提供了一套强大的工具集,使艺术家和设计师能够...
标题 "PG2Ray.rar" 暗示我们讨论的是一个名为 "PG2Ray" 的程序或工具,它被压缩在RAR格式的文件中。RAR是一种常见的压缩格式,用于减少文件大小以便于存储和传输。RAR文件可以包含一个或多个文件,并且通常具有密码...
根据提供的文件信息,以下是关于机器学习Ray框架的详细知识点: 1. 强化学习(RL)的应用需求:机器学习的应用正在从传统的监督学习转向强化学习,其中应用程序需要在动态环境中与环境交互并学习。这些应用程序面临...