.Net多线程与Windows Forms编程2007-12-29 11:25:06 来源:中国自学编程网 作者: 点击:
1 UI线程执行耗时操作 UI线程被阻塞 无法响应窗体消息队列中的其他消息。 2 非UI线程修改UI属性 由于窗体资源也属于临界资源 所以有互斥访问的机制。3 线程的同步问题 线程A等待线程B执行完毕后才能开始执行。 ![]() 1 UI线程执行耗时操作 UI线程被阻塞 无法响应窗体消息队列中的其他消息。
2 非UI线程修改UI属性 由于窗体资源也属于临界资源 所以有互斥访问的机制。 3 线程的同步问题 线程A等待线程B执行完毕后才能开始执行。 问题1的解决方法: 解决方法只有一种,就是开启新线程执行耗时操作,使原界面线程仍能够响应窗体消息队列中的用户消息及系统消息。 开启新线程的方式有以下各种: 1) 使用System.Threading.Thread类与System.Threading.ThreadStart委托或System.Threading.ParameterizedThreadStart委托来实现开启新线程。 ThreadStart委托的类型: void ThreadStart(void); ParameterizedThreadStart委托的类型: void ParameterizedThreadStart(object[]); ThreadStart委托可以指向一个无参数无返回值的方法。 ParameterizedThreadStart委托可以指向一个有参数无返回值的方法。 Thread类实例化的时候可以向构造函数传入ThreadStart委托的实例或ParameterizedThreadStart委托的实例,然后使用Thread.Start()以异步方式调用一个方法。 2) 为需要异步执行的耗时方法定义一个委托,使用该委托的实例的BeginInvoke方法来异步调用该方法,BeginInvoke方法附带了AsyncCallback类型的回调函数委托以及object类型的参数。 然后可以在AsyncCallback类型的回调函数中使用EndInvoke方法来得到异步方法的返回值。 3) 可以使用System.Timers.Timer定时器类来实现在新线程中执行耗时操作,System.Timers.Timer定时器不同于System.Windows.Forms.Timer定时器,System.Timers.Timer定时器的定时事件的响应函数并不是在调用定时器Start方法的线程中去执行。 4) 可以使用BackgroundWorker组件来实现在新线程中执行耗时操作(通过订阅DoWork事件). 问题2的解决方法 以下代码是.NetFramework 2.0类库中避免多线程修改界面造成的临界资源死锁问题的代码。 System.Windows.Forms.Control.get_Handle方法的内部实现 public IntPtr get_Handle() { if ((checkForIllegalCrossThreadCalls && !inCrossThreadSafeCall) && this.InvokeRequired) { throw new InvalidOperationException(SR.GetString("IllegalCrossThreadCall", new object[] { this.Name })); } if (!this.IsHandleCreated) { this.CreateHandle(); } return this.HandleInternal; } 在修改每个控件的属性的时候,都会先调用get_Handle方法获取一个操作句柄,在该方法内部会判断Control类的静态成员CheckForIllegalCrossThreadCalls的值(该成员用来表示是否启用安全模式,安全模式的意思就是禁止跨线程修改界面属性来避免多线程访问临界资源死锁的问题),第二个判断的属性是InvokeRequired属性(该属性用来表示当前方法是否是在跨线程调用)。 所以我们可以通过修改CheckForIllegalCrossThreadCalls属性为False来关闭安全模式,但有可能造成线程死锁问题。 解决方法只有两个
![]()
|
|
||||
|
|
||||
|
|
|
||||
|
|
||||
|
|
|
||||
|
|
||||
|
|