一、为什么要使用多线程?
1、提升系统的吞吐量,也即效率(大多数课本上都会这样讲,我也认为确实可以,但实际中应用较少使用到)
2、使UI保持响应;
3、在整合系统中,一个系统在运行中等待另一个系统执行结果的返回;(其实也是保持响应)
二、使用线程的难点:
1、线程控制(也即调度,这个基本上我们控制不了,操作系统有自己的调度策略)
2、线程间通信(线程同步)
3、临界资源问题(也即线程互斥,其实如何发现临界资源也是一个话题,不是吗?)
三、C#中开启多线程的方法:
1、UI控件中的BeginInvoke方法
这个方法可以在不阻塞UI的情况下(即UI可以正常响应用户的操作),指定委托指向的特定方法。
通常来将调用这个方法,一般是下面两种情况:
(1)在保持ui用户响应的前提下,去执行一个非常耗时的方法;
(2)在非UI线程执行中,想要报执行结果显示在UI中,这时可以使用这个方法,来达到切换线程的目的
2、委托的BeginInvoke方法
这个是一个比较好理解的逻辑结构实现的一种多线程方法;
实现步骤:
(1)定义开启多线程的委托,即准备要进行BeginInvoke的;(主要是针对要调用的耗时的外部方法的签名进行定义)
如:delegate string WSTestMethodHandler();
(2)定义线程切换使用的委托;(这个主要作用是:在多线程执行完毕后,回调函数中,将非UI线程转换为UI线程)。
如:delegate void AsyncCallerSwitcher(IAsyncResult a);
(3)定义具体的耗时方法
如:string TestMethod();
(4)定义具体的回调函数(这里有个小trick(戏法,把戏,技巧),就是这个函数同时作为回调,和切换线程的之用,也即对于回调函数和切换线程的函数我们可以只定义一个函数,之所以这样,是因为这两个方法接口是可以统一的。当然这里需要使用到InvokeRequired属性,以确定是否可以直接对UI进行操作)
如:void TestMethodCallBackMethod(IAsyncResult a)
(5)定义开启多线程委托的实例,即将委托指向具体的某个方法,即将(3)步中的方法名作为参数,传递给(1)步定义的委托,产生一个委托实例;
如:WSTestMethodHandler tmpAsyncCaller = new WSTestMethodHandler(TestMethod);
(6)定义回调函数的委托实例,即AsyncCallback系统委托的实例,这个委托的参数为IAsyncResult接口类型;
如:AsyncCallback tmpCallBacker = new AsyncCallback(TestMethodCallBackMethod);
3、Thread类
4、使用BackgoundWorker组件
5、使用System.Threading.ThreadPool.QueueUserWorkItem方法
四、在实践中发现真谛:
1、一个用多线程保持UI响应的例子;
2、一个用多线程整合WS的例子;
线程有诸多好处,这是大家有目共睹的了,但是它的难以控制也是大家痛心疾首的问题,
线程控制的几个方式:
1、回调函数
2、AutoResetEvent,ManualResetEvent
3、其实线程对象自身也包含有同步方法,这个要研究一下;
/*
* AutoResetEvent和ManualResetEvent区别:
* AutoResetEvent会在每次调用完WaitOne方法后,自动设置AutoResetEvent对象为阻止状态
* 即在成功通过WaitOne后,再次调用WaitOne时会阻塞
* ManualResetEvent在通过WaitOne方法后,再次调用WaitOne时不会阻塞,需要手动调用Reset方法
*/
/*
*初始值不同,带来的不同执行行为
*AutoResetEvent初始值为false
*这个会导致在第一调用WaitOne方法时就被阻塞
AutoResetEventThread thread will sleep 2000 seconds
AutoResetEventThread running at 2012-10-23 10:58:34.759
Main thread running at 2012-10-23 10:58:36.793
* AutoResetEvent初始值为true
* 这个会导致第一次调用WaitOne方法时候不会被阻塞
* 在下面的时间可以看出Main thread(2012-10-23 11:00:46.533)是先于AutoResetEventThread(2012-10-23 11:00:46.558)执行
AutoResetEventThread thread will sleep 2000 seconds
AutoResetEventThread running at 2012-10-23 11:00:46.558
Main thread running at 2012-10-23 11:00:46.533
*/
//使用此方法确保线程已终止。如果线程不终止,则调用方将无限期阻塞。
//如果调用 Join 时该线程已终止,此方法将立即返回。
//此方法更改调用线程的状态以包括 ThreadState.WaitSleepJoin。
//对处于 ThreadState.Unstarted 状态的线程不能调用 Join
//ThreadStateException 调用方尝试联接一个处于 ThreadState.Unstarted 状态的线程。
//ThreadInterruptedException 此线程在等待时被中断。
待完善!!!!