第14章 线程和异步编程(4)

2019-04-23 14:38

《基于VB.NET的.NET Framework程序设计》教学指导手册—详细教案

锁,这时候写锁就起作用了,AcquireWriterLock就会返回,返回以后就会进入写操作区域。在这个区域内部,所有的读操作都是禁止的,所以进入Write()方法的try这个代码区域以后,所有的AcquireReadLock都会被阻塞,直到调用ReleaseWriterLock()后,其他线程的AcquireReadLock才能返回,以便进入Read()区域。这个类的使用并不复杂,但如果要自己实现这个类,相对来说是比较麻烦的,事实上可以通过Mutex类来实现ReadWriteLock,但代码量会很多。 .Net为开发人员提供了这样一个类,什么情况下需要使用ReadWriteLock类呢? .Net里有一个System.Collection的命名空间,包含了各种各样的集合类,可以把很多数据都放在这个集合里面,比如队列、arraylist等等,这些都是集合数据类型。在操作集合数据类型时,例如从队列的一端向这个队列添加数据,并从另一端取出数据,单线程数据操作很简单,但如果多线程要操作这个集合类型时,就会涉及到同步的问题,有一些集合数据类型应该支持同时从集合里取数据,但修改集合中的数据时,只能允许一个线程操作,此时用到ReadWriteLock类。将这个类和集合数据类型配合就可以在保证线程安全的情况下,实现多个进程的同步操作。 需要注意的是,在.Net类库里,每一个类都会标明一个类型安全的特性,也就是说在多线程操作这个类时,如果文档里将这个类定义为类型安全的,那么就说明多线程可以放心地操作这个对象;如果不是类型安全的,那么在操作类对象时,必须进行线程同步。 在使用集合类型时,要先注意使用的集合类型。在调用大多数数据类型的方法,尤其是成员方法时,必须通过同步代码来保证对这些操作是线程安全的,因为大部分集合类型都是线程不安全的,必须通过同步,无论是16

第14章 线程和异步编程

手动同步还是同步区域,来保证访问数据类型时是线程安全的。 讲解课本:14.3.4 讲授: 阅书:14.3.5 在类库的文档中,每一个类都会有一个专门幻灯:第20页 的条目TypeSafety,即类型安全性,通过类型安全性显示该类的线程安全。集合数据类 型通常来说都不是线程安全的,只有Hashtable是例外。通常来说,开发人员需要使用Monitor、Mutex或者Synchronization属性对线程访问的方法做一个包装,以保证类型安全。 在使用集合数据类型的时候,需要注意,基本上所有的集合数据类型如Hashtable、arraylist等都有Synchronized属性,该属性会返回一个和原来类型完全一样的,但是线程安全的包装对象。例如,默认情况下,arraylist可以容纳很多数据,但是它不是类型安全的,因此可以调用arraylist. Synchronized这个属性,得到一个同步的arraylist类型的变量。比方说,现在有一个arraylist变量A,可以通过A1=A. Synchronized,返回一个类型安全的arraylist变量:A1。经过同步的arraylist对象,跟原有对象的内容是一样的,只是当使用A1去访问集合中的数据时,所有的方法都是经过线程同步的,这样就可以保证集合的线程安全。 使用Synchronized属性是一种比较方便的同步方法,当然也可以直接使用手动方式,如Mutex、Monitor等实现同步,但这样做会增加编码难度,且容易出错;手动方式也有好处,它可以从更细节的层面上去控制同步代码。开发人员应该根据需求和自己的情况,决定使用简单的Synchronized属性还是Monitor类。 讲解课本:14.3.5 17

《基于VB.NET的.NET Framework程序设计》教学指导手册—详细教案

14.4线程的特殊主题

教学提示 : 本节主要达到目的。

? 了解Timer类的一些技术点。(略讲) ? 了解线程池的相关技术。(精讲)

? 了解使用多线程与Windows窗体控件的方法。(略讲) ? 了解一些使用线程的最佳实践。(略讲) 教学内容 演示: 课本14.4.1的代码案例 讲授: 阅书:14.4.2 教学方法 幻灯:第23页 提示 课堂演示 MTA相关知识参考: http://lunwen.eliu.info/js7.htm 首先介绍线程池的概念。什么是线程池,线幻灯:第24页 程池的用途是什么,它和普通的线程有什么不同?线程池实际上和计算机的进程相关, 也就是说一个线程池是和一个进程相关的。 程序运行时,会有一个线程池和这个程序相关联,进程里的所有代码都可以利用线程池的功能。之所以把它叫做线程池,是因为对象内部包含了很多预先创建好的线程。使用线程池,就不需要事先编写线程函数,然后创建线程,也不需要把线程函数和线程关联起来。开发人员只要调用线程池的一个方法,例如,调用线程池ThreadPool类的QueueUserWorkItem方法,就可以把一个包装在某人委托中的任务传递到线程池内部,然后,线程池就会自动把这个任务分配给池中空闲的线程,并让该线程运行。 总的来说,线程池的使用是比较简单的,尤其是当多个不同的任务都要依靠多线程来运行时。但线程池也有一些问题,因为开发人员没办法指定和创建某一个线程,所以就不能指定线程优先级;而且有些线程可能会有一些比较独特的特性,比如运行时间很长等等,这时也不适合使用线程池;程序运行时,如果开发人员需要了解并控制正在运行18

第14章 线程和异步编程

的线程,那么也不能使用线程池,因为使用线程池的话,就不知道哪个线程运行特定的任务,也就无法对它做调度。另外,执行这个线程时,需要使用单元线程来执行任务的时候也要注意,因为线程池默认是使用MTA多线程单元来执行,所以这也是我们需要注意的。通常情况,什么程序会在单元线程里运行?消息处理机制的Windows程序的主线程需要在单元线程里运行,因为它需要与窗体和控件交互,需要处理Windows程序的消息,所以不能把它放在多线程单元里运行,因此,当线程在单线程单元里运行时,也不能使用线程池。 使用线程池时,可以对线程池里的线程使用IOCompletionCallback委托。一般来说,外部设备的速度相对较慢,程序会使用线程来执行读写数据等IO操作,但又不知该IO操作如何能执行完毕。这时候可以用IOCompletionCallback唤醒线程池里的线程,当IO操作完毕,获得数据后,线程池里的线程就会被这个异步委托唤醒,这样线程池里的线程就能立刻作出处理。 讲解课本:14.4.2 讲授: 阅书:14.4.3 前面介绍了线程池,它是一种比较简单的,幻灯:第25页 通过避免直接创建线程而利用多线程功能 的对象。下面要研究多线程和Windows窗体控件交互时会遇到的问题?需要注意的 是,Windows窗体控件只能在创建它们的线程里被直接控制,也就是说,主线程才能直接调用窗体控件、修改窗体控件的属性、调用窗体控件的方法,比如显示对话框等操作。从其他线程调用窗体控件的操作会被认为是不安全的,可能导致程序出现各种各样难以预料的结果。如果后台线程和额外创建的其他线程需要调用窗体控件,那么必须通过一个特殊的方法。可以使用MethodInvoker这个委托,从后台线程调用Windows窗体控件,每一个控件里都会有一些线程安全的方法,如Invoke、 BeginInvoke和EndInvoke,通过这些方法

19

《基于VB.NET的.NET Framework程序设计》教学指导手册—详细教案

去调用线程就是安全的。 看下面代码示例。要调用窗体控件的某一个方法,比如要更新窗体的进度条,那么就要调用进度条控件的UpdateProgress方法,其他线程不能直接调用它,因此先使用MethodInvoker委托,把UpdateProgress包装起来,即先创建了一个MethodInvoker委托,它指向UpdateProgress方法。然后调用aFormControl控件的BeginInvoke方法,并且把刚刚创建的MethodInvoker对象mi传递给BeginInvoker方法。这样就通过MethodInvoker做了一个间接的包装,保证MethodInvoker内部可以控制线程的同步,对UpdateProgress方法的调用是安全的,此后再通过线程的BeginInvoke或者MethodInvoker去调用UpdateProgress方法就是安全的了。 用后台线程调用窗体控件时都会使用这种方式。首先用MethodInvoker创建一个委托,指向要调用的函数,然后再用控件的BeginInvoke方法调用MethodInvoker这个委托来完成方法调用。需要注意的是,在高级编程课程本章后的练习中会有一些多线程的习题,该习题要在多线程编程中调用窗体控件,并在窗体控件上显示并更新数据信息,在课后练习题中会用到上面所讲的内容。 讲解课本14.4.3 讲授: 现在我们来看一下有哪些推荐的操作: 讲解课本:14.4.4 阅书:14.4.4 幻灯:第26页 20


第14章 线程和异步编程(4).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:汽车销售管理系统报告 - 图文

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: