第6章进程与线程开发程序设计_第1页
第6章进程与线程开发程序设计_第2页
第6章进程与线程开发程序设计_第3页
第6章进程与线程开发程序设计_第4页
第6章进程与线程开发程序设计_第5页
已阅读5页,还剩34页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

2013.07第6章进程与线程开发程序设计

学习要点1.了解进程与线程的基本技术2.掌握C#进程应用程序开发方法3.掌握C#常用多线程互斥与同步的应用程序开发方法4.掌握C#跨线程访问控件的基本方法6.1进程与线程概述1.进程

Windows是一个多任务的系统,它能够同时运行多个程序,其中的每一个正在运行的程序就称为一个“进程”。Windows2000及其以上版本,可以通过任务管理器查看系统当前运行的程序和进程。2.线程对于同一个进程,又可以分成若干个独立的执行流,这样的流则被称为“线程”。线程是操作系统向其分配处理器时间的基本单位,它可以独立占用处理器的时间片,同一进程中的线程可以共享其进程的资源和内存空间。每一个进程至少包含一个线程。3.并发进程和线程技术的引入,为实现系统或应用程序的并行性提供了重要的技术基础。所谓的“并行”又被称为“并发”,是指系统或应用程序同时处理多个事务的运行过程。对于单处理器的计算机系统来说,由于单个CPU在任何时刻只能执行一个线程,所以,这种计算机系统的并发,实际上是通过操作系统在各个正在执行的线程之间切换CPU,以分时处理的方式实现表面形式上的并发,只是因为其切换的速度快且处理能力强时,用户直观感觉不到而已。当然,对于多处理器的计算机系统,其多个CPU之间既有相互协作,又有独立分工,所以,它们在各自执行一个相应线程时可以互不影响,同时进行,进而实现真正意义上的并发处理。6.2进程开发技术

进程与程序不同,它是程序执行时的标志,而不是程序的静态版本。用户创建一个进程后,操作系统就将程序的一个副本装入计算机中,然后启动一个线程执行该程序。尽管.NET环境中仍然使用进程和线程,但管理代码的应用程序边界是应用程序域。通用语言运行库(CLR)强制隔离应用程序域,使一个进程中可以有多个隔离的应用程序。在C#中,可通过两种方法来开发进程程序:C#的System.Diagnostics命名空间下的Process类专门用于完成系统的进程管理任务,通过实例化一个Process类,就可以启动一个独立进程。C#的进程组件(Process)提供了对本地和远程进程的访问功能,并启用本地进程的开始和停止功能。6.2进程开发技术开发一个利用进程控制应用程序的设计示例。通过点击相应的按钮,既能方便地打开Windows操作系统附件中的“计算器”或此前开发的“上机自测系统”,也能将它们随时关闭。【示例代码:chpt6-2\CProcess】(1)新建一个C#项目,其Windows应用程序命名为CProcess,并从“公共组件”工具箱中拖放相应控件到新建窗体Form1上。(2)按照表所示的内容,设置各控件的相应属性值。控件(Name)属性属性新值button1NamebtnCalculatorStartText启动一个计算器button2NamebtnCalculatorStopAllText关闭全部计算器button3NamebtnSelfExamStartText启动一个上机自测系统button4NamebtnSelfExamStopAllText关闭全部上机自测系统6.2进程开发技术(3)从“组件”工具箱中拖放1个Process组件到该窗体上,并将它们的Text属性分别设置为CalculatorProcess。(4)首先,从Windows操作系统的“开始”→“所有程序”→“附件”→右键点击“计算器”,打开“快捷方式”属性对话框,如图6-2所示,将其“目标”文件及其前面的“\”合并至“起始位置”之后,拷贝全部“起始位置”内容,并点击“取消”关闭计算器属性面板。利用进程控制应用程序设置进程启动信息6.2进程开发技术(5)分别编写通过C#进程组件启动和关闭计算器的相应代码。usingSystem.Diagnostics;usingSystem.Threading;//启动一个Windows计算器privatevoidbtnCalculatorStart_Click(objectsender,EventArgse){CalculatorProcess.Start();}//关闭全部已启动的Windows计算器privatevoidbtnCalculatorStopAll_Click(objectsender,EventArgse){//创建一个Process组件的数组

Process[]CalculatorProcess;//将所建数组与指定进程名称(calc)的所有进程资源相关联

CalculatorProcess=Process.GetProcessesByName("calc");//遍历当前启动程序中,查找包含指定名称的进程

foreach(ProcessinstanceinCalculatorProcess){//终止当前进程,关闭应用程序窗体

instance.CloseMainWindow();}}6.2进程开发技术(6)分别编写通过实例化一个C#的Process类,启动和关闭上机自测系统的相应代码。usingSystem.IO;//启动一个上机自测系统privatevoidbtnSelfExamStart_Click(objectsender,EventArgse){FileInfofInfo=newFileInfo(@"E:\C#程序设计\教材源代码

\chpt5-1\selfExam\selfExam\bin\Debug\selfExam.exe");if(fInfo.Exists){//实例一个Process类,启动一个独立进程

ProcessprcsSelfExam=newProcess();//Process有一个StartInfo属性,这是ProcessStartInfo类,包括一些 方法和属性

//待启动的程序文件

prcsSelfExam.StartInfo.FileName=fInfo.FullName;//启动进程

prcsSelfExam.Start();}else{MessageBox.Show("文件:"+fInfo.FullName+"不存在!");}}6.2进程开发技术//关闭已启动的所有上机自测系统{//创建一个Process组件的数组

Process[]SelfExamProcess;//将所建数组与指定进程名称(selfExam)的所有进程资源相关联

SelfExamProcess=Process.GetProcessesByName("selfExam");//遍历当前启动程序中,查找包含指定名称的进程

foreach(ProcessinstanceinSelfExamProcess){//终止当前进程,关闭应用程序窗体

instance.CloseMainWindow();}}6.3线程开发基础知识1.线程的引入你的银行账户余额为:100,000同时有两个人在给你汇款:50,000第一个人从数据库中把你的余额读出来:100,000第一个人把你的余额修改成:150,000第二个人从数据库中把你的余额读出来:100,000第二个人把你的余额修改成:150,000第一个人把你的余额存入数据库:150,000第二个人把你的余额存入数据库:150,000有5,000不翼而飞了?2.命名空间引用

.NET将关于多线程的功能定义在System.Threading命名空间中。因此,要使用多线程,必须先引用此命名空间(usingSystem.Threading;)。在这个命名空间下,包含了用于创建和控制线程的类Thread。一个Thread的实例表示一个线程,也就是一个执行序列。通过实例化一个Thread对象,就可以创建一个线程。6.3线程开发基础知识2.线程创建与控制在System.Threading.Thread类中,包含了以下几种方法,用于创建和控制线程:创建线程在C#中使用Thread类创建线程时,只需提供线程入口即可(线程入口使程序知道该让这个线程去做什么)。线程入口是通过ThreadStart代理(delegate)来提供的,我们可以把ThreadStart理解为一个函数指针,指向线程要执行的函数,示例代码如下:Threadthread1=newThread(newThreadStart(Method1));启动线程顾名思义,“启动线程”就是并启动一个新建的线程。当调用C#的Start()方法后,线程就开始执行ThreadStart所代表或者说指向的函数,示例代码如下:

thread1.Start();

其中的Method1是将要被新线程执行的函数。6.3线程开发基础知识销毁线程因为计算机的资源是有限的,所以,当一个线程的任务完成后,如果此后将不再被使用它,就应及时释放它所占用的系统内存,也即销毁它。通过调用Abort()方法销毁一个线程。所以,为了不徒劳去销毁一个非活线程,在销毁一个线程之前通常先利用IsAlive属性来判断它是否还处于活动状态,而后再采取销毁措施,示例代码如下:if(thread1.IsAlive==true){thread1.Abort();}休眠线程开发线程时,有时不希望它一直连续运行,而是以一定的周期运行,或者想让它延迟一段时间,以等待其他线程运行,这时可利用Sleep()方法,将“当前线程”临时终止或休眠一段时间(毫秒)。如Thread.Sleep(1000);就是让线程休眠1秒钟。6.3线程开发基础知识挂起线程Suspend()方法用来挂起一个正在运行的线程,直到调用Resume()方法,此线程才可以继续执行。如果线程已挂起,则此方法不起作用,所以,在准备执行线程挂起操作之前,先要判断其当前是否处于运行状态,示例代码如下:if(thread1.ThreadState=ThreadState.Running)

{

thread1.Suspend();

}恢复线程Resume()方法用来恢复已经挂起的线程,以让它继续执行,但若线程并未挂起,则此方法不会起作用,所以,在准备执行线程挂起操作之前,先要判断其当前是否处于挂起状态,示例代码如下:if(thread1.ThreadState=ThreadState.Suspended)

{

thread1.Resume();}终止线程Thread.Interrupt()用来终止处于Wait、Sleep或者Join状态的线程。阻塞线程Join()用来阻塞调用线程,直到某个线程终止时为止。6.3线程开发基础知识3.Thread的公共属性属性名称说明ApartmentState获取或设置线程的单元状态CurrentContext获取线程正在执行的当前上下文CurrentCulture获取或设置线程的区域性CurrentPrincipal获取或设置线程当前负责人CurrentThread获取当前正在运行的线程CurrentUICulture获取或设置资源管理器使用的当前区域性IsAlive获取一个值,该值指示当前线程的执行状态。如果此线程已启动并且尚未正常终止或中止,则为true;否则为falseIsBackGround获取或设置一个值,该值指示某个线程是否为后台线程IsThreasPoolThread判断是否是线程池线程Name获取或设置线程名称Priority获取或设置一个值,该值指示线程的调度优先级ThreadState获取一个值,该值包含当前线程的状态6.3线程开发基础知识4.ThreadState属性:属性值说明Aborted线程已停止AbortRequested线程的Thread.Abort()方法已被调用,但是线程还未停止Background线程在后台执行,与属性Thread.IsBackground有关;不妨碍程序的终止Running线程正在正常运行Stopped线程已被停止StopRequested线程正在被要求停止Suspended线程已被挂起(此状态下,可以通过调用Resume()方法重新运行)SuspendRequested线程正在要求被挂起,但是未来得及响应Unstarted未调用Thread.Start()开始线程的运行WaitSleepJoin线程因调用了Wait()、Sleep()或Join()等方法处于封锁状态6.3线程开发基础知识5.线程优先级在C#中,一个线程的优先级由高到低可分为5种:Highest、AboveNormal、Normal、BelowNormal和Lowest。对于新创建但未指定优先级的线程,系统默认设置其优先级为Normal。示例代码如下://将线程的优先级设置为最高优先级

thread1.Priority=ThreadPriority.Highest;6.3线程开发基础知识6.示例程序设计在应用程序开发过程中经常会遇到线程的例子,例如,某个后台操作比较费时间,我们就可以启动一个线程去执行这个费时的操作,同时仍可使当前程序继续执行。以下是一个简单的线程应用程序开发示例,在这个程序中,有两个相互独立的线程,各自进行0~999的累加计数并显示,每次计数到最大值(999)时,将暂停3秒,而后又重新开始0~999的计数和显示。在此期间,如果按下“终止线程”按钮,计数将停止;否则,上述过程将循环往复。【示例代码:chpt6-3a\MThreadTest1】6.4多线程开发技术6.4.1多线程概述实际上,在上一节的线程开发示例(chpt6-3a)中,就包含了多个线程(两个线程分别实现累加计数的功能)。1.多线程所谓多线程,是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。浏览器就是一个典型的多线程的例子,在浏览器中,你可以在下载文件的同时滚动页面,也可在打开一个新页面的同时播放动画和声音,甚至同时打印网页等。2.多线程的好处多线程的好处在于可以提高CPU的利用率,因为,在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,这样就大大提高了程序的效率。6.4多线程开发技术3.多线程的不利然而我们也必须认识到线程本身可能影响系统性能的不利方面,这些方面主要包括:线程也是程序,所以线程需要占用内存,线程越多占用内存也越多。多线程需要协调和管理,所以需要CPU时间跟踪线程。线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题。线程太多会导致控制太复杂,最终可能造成很多Bug。6.4.2多线程互斥与同步概述1.多线程互斥在多线程的应用程序中,由于受资源的有限性限制,或者为了避免多个线程同时访问共享资源而产生信息处理矛盾或错误,必须采取排他性的资源访问方式一次只允许一个线程对其进行访问共享的资源,就是多线程的互斥。互斥无法限制线程对资源的访问顺序,即访问是无序的。2.多线程同步在多线程的应用程序中,多个线程之间可能需要相互协作,以便共同完成相应的任务,即某些线程需要其他线程提供的资源,或反之。这种多个线程之间相互配合、协同工作的方式,就是多线程的同步。通常情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个线程同时访问资源。6.4.3多线程互斥程序开发在C#中,可以利用Lock关键字、Monitor类(监视器)、Mutex类(互斥器)以及ReaderWriterLock类等多种方法实现多线程的互斥。1.lock:一般用于多个线程共享同一个代码段的情况概述lock是C#中的关键字,它将语句块标记为一个临界区,确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。其执行过程是先获得给定对象的互斥锁,然后执行相应语句,任务完成后再释放该锁。通常应避免锁定public类型的对象,否则实例将超出代码的控制范围。最佳做法是定义private对象来锁定,或privatestatic对象变量来保护所有实例所共有的数据。用法关键字lock定义如下:lock(object)@//互斥段的代码Statement_Block或者:lock(object){@//互斥段的代码DoSomething();……}6.4.3多线程互斥程序开发示例程序设计在此示例中,当点击“启动线程”按钮后,程序将通过两个线程同时向同一个文本框分别写入字符a和A,而当点击“停止线程”按钮后,写入过程将随时停止。显然,这个共用的文本框就相当于一个共享资源,程序执行过程中如果不运用必要的线程互斥技术,将可能出现访问冲突或数据处理错误的问题,为此,必须运用必要的线程互斥技术。【示例代码:chpt6-4a\ThreadMutex1】(详细代码见教材)6.4.3多线程互斥程序开发2.Monitor:静态类,一般用于多个线程之间进行同步概述Monitor提供了与lock类似的功能,它通过向单个线程授予对象锁来控制对该对象的访问。用法Monitor类的2个常用方法如表所示。除此之外,还有以下方法:Wait:释放对象上的锁并阻塞当前线程,直到它重新获取该锁Pulse(object)/PulseAll(object):向阻塞线程队列(由于该object而转入阻塞状态的所有线程,也就是那些执行了Wait(object)的线程,存放的队列)中第一个/所有线程发信号,该信号通知锁定对象的状态已更改,并且锁的所有者准备释放该锁。收到信号的阻塞线程进入就绪队列中,以便它有机会接收对象锁。注意,接受到信号的线程只会从阻塞中被唤醒,并不一定会获得对象锁方法说明Enter()在指定对象上获取排他锁Exit()释放指定对象上的排他锁注意:以上所有方法都只能在临界区内被调用,换句话说,只有对象锁的获得者能够正确调用它们,否则会引发SynchronizationLockException异常。

注意:如果Exit和Enter函数的调用次数不匹配,则该锁不会被正确释放。

6.4.3多线程互斥程序开发Monitor类的基本用法如下://obj是一个private级的内部变量,不表示任何意义,只是作为一种“令牌”//的角色。如果要锁定一个类的实例,可以使用thisprivateSystem.Objectobj=newobject();…System.Threading.Monitor.Enter(obj);try{//互斥段的代码DoSomething();……}//对象非正常释放catch(ThreadAbortException等异常){System.Threading.Monitor.Exit(obj);}//对象正常释放System.Threading.Monitor.Exit(obj);6.4.3多线程互斥程序开发示例程序设计说明:在此,仍然设计一个chpt6-4a所示功能的示例。【示例代码:chpt6-4b\MThreadTest1】设计步骤如下:(1)复制项目文件夹chpt6-4a,并将其重新命名为chpt6-4b。(2)设置窗体的Text的属性值为“多线程互斥(Monitor)”。(3)在原项目程序基础上,进行相应的代码调整(修改或删除部分均以/*…*/进行注释)(详细代码见教材)6.4.3多线程互斥程序开发3.Mutex:一般用于多进程之间的同步概述在使用方法上,Mutex与Monitor类似。但是,由于Mutex不具备Wait、Pulse和PulseAll几种方法,因此,它不能实现类似Monitor的唤醒功能。另外,因为互斥体Mutex属于内核对象,进行线程同步时,线程须在用户模式和内核模式间切换,所以,需要的互操作转换更耗资源,效率较低。不过Mutex有一个比较大的特点,Mutex是跨进程的,因此可以在同一台机器甚至远程的机器上的多个进程上使用同一个互斥体。用法类似于Monitor,在Mutex类中也有2个常用方法,如下表所示。方法说明WaitOne()捕获互斥对象ReleaseMutex()释放被捕获的对象6.4.3多线程互斥程序开发Mutex类的基本用法也与Monitor类似,如下://对象实例化一个Mutex对象(不需声明一个“令牌”)privateMutexmut=newMutex();…mut.WaitOne();try{//互斥段的代码DoSomething();……}//对象非正常释放catch(ThreadAbortException等异常){mut.ReleaseMutex();}//对象正常释放mut.ReleaseMutex();6.4.3多线程互斥程序开发示例程序设计说明:在此,仍然设计一个chpt6-4b所示功能的示例。由于Mutex的用法类似于Monitor,所以,只需在示例chpt6-4b的基础上适当修改代码即可。【示例代码:chpt6-4c\ThreadMutex1】设计步骤如下:(1)复制项目文件夹chpt6-4b,并将其重新命名为chpt6-4c。(2)设置窗体的Text的属性值为“多线程互斥(Mutex)”。(3)在原项目程序基础上,进行相应的代码调整(增加、修改或删除部分均以/*…*/进行注释)。实际上,只需首先实例化一个Mutex对象,如:privateMutexmut=newMutex();然后,分别将原程序中的Monitor.Enter(this);代之以mut.WaitOne();,Monitor.Exit(this);代之以mut.ReleaseMutex();即可。(详细代码见教材)6.4.3多线程互斥程序开发Mutex有个最常见的用途:用于控制一个应用程序只能有一个实例运行:参见程序:SingleObject6.4.3多线程互斥程序开发4.ReaderWriterLock概述.Net提供的ReaderWriterLock定义了支持单个写线程和多个读线程的锁,用于同步对资源的访问。利用读写锁,在任一特定时刻,允许多个线程同时进行读操作,或者允许单个线程进行写操作。用法ReaderWriterLock类的4个常用方法如下表所示。方法说明AcquireWriterLock(intmillisecondsTimeout)或AcquireWriterLock(TimeSpantimeout)超时值使用整数或者TimeSpane:-1表示线程将无限期等待直到获得锁为止,对于指定整数超时的方法,可以使用常数Infinite。0表示线程不等待获取锁,如果无法立即获取锁,方法将返回。大于0表示要等待的毫秒数。AcquireReaderLock(intmillisecondsTimeout)或AcquireReaderLock(TimeSpantimeout)(超时值用法同AcquireWriterLock方法)ReleaseWriterLock()释放编写锁ReleaseReaderLock()释放读取锁6.4.3多线程互斥程序开发ReaderWriterLock的基本用法如下://创建阅读器和编写器锁privateReaderWriterLockrwl=newReaderWriterLock();…//写操作rwl.AcquireWriterLock();try{//互斥段的代码DoSomething();……}//写对象非正常释放catch(ThreadAbortException等异常){rwl.ReleaseWriterLock();}//写对象正常释放rwl.ReleaseWriterLock();…6.4.3多线程互斥程序开发//读操作rwl.AcquireReaderLock();try{//互斥段的代码DoSomething();……}//读对象非正常释放catch(ThreadAbortException等异常){rwl.ReleaseReaderLock();}//读对象正常释放rwl.ReleaseReaderLock();6.4.4多线程同步程序开发1.类比示例简析多工种协同生产示意图:2.线程示例简析多线程同步:6.4.4多线程同步程序开发3.示例程序设计【示例代码:chpt6-5\ThreadSynchronize】窗体Form1及其各控件的属性设置

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论