[转].Net多线程与Windows Forms编程笔记

多线程Winform编程会带来的常见问题

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来关闭安全模式,但有可能造成线程死锁问题。

解决方法只有两个
1) 设置CheckForIllegalCrossThreadCalls属性为False,关闭.net的安全模式,在对界面属性修改的代码加上lock,来实现同一时间仅有一个线程修改界面属性。
2) 在设置界面属性的方法中询问InvokeRequired属性,如果是非界面线程修改界面属性,则让界面线程来调用设置界面属性的方法。(这个方法是MSDN实例中惯用的方法,也是BackgroundWorker等组件的内部实现方式)


推荐大家使用BackgroundWorker来实现耗时操作的辅助线程以及跨线程修改界面属性等操作,关于BackgroundWorker的具体使用方法见 一日一练 之 BackgroundWorker
http://www.cnblogs.com/coderlee/archive/2007/12/27/1017620.html

posted @ 2007-12-28 14:53  Lorn  阅读(421)  评论(0编辑  收藏  举报