第02章进程与线程_第1页
第02章进程与线程_第2页
第02章进程与线程_第3页
第02章进程与线程_第4页
第02章进程与线程_第5页
已阅读5页,还剩61页未读 继续免费阅读

下载本文档

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

文档简介

1、1 1第第2章章 进程与线程进程与线程2.1 进程与线程的基本概念进程与线程的基本概念2.2 进程管理(进程管理(Process类)类)2.3 线程管理(线程管理(Thread类)类)2.4 线程同步与线程池线程同步与线程池2.5 BackgroundWorker组件组件2 2本章重点本章重点本章教学目的本章教学目的 通过对进程、线程基本知识以及通过对进程、线程基本知识以及BackgroundWorker组件组件的介绍,使学生对相关内容有一个感性认识。的介绍,使学生对相关内容有一个感性认识。本章教学要求本章教学要求(1)掌握进程查看、启动、停止的基本方法;)掌握进程查看、启动、停止的基本方法;

2、(2)掌握线程创建、启动、终止的基本方法;)掌握线程创建、启动、终止的基本方法;(3)掌握开辟多线程的基本方法;)掌握开辟多线程的基本方法;(4)掌握在一个线程中引用其他线程中的控件的方法;)掌握在一个线程中引用其他线程中的控件的方法;(5)了解其他内容。)了解其他内容。3 32.1 进程与线程的基本概念进程与线程的基本概念 进程进程 正在执行的程序称为进程。正在执行的程序称为进程。 与进程相关的信息包括:进程标识(进程与进程相关的信息包括:进程标识(进程ID)、文件名、执)、文件名、执行的程序和数据,运行时间、在存储器中的位置、占用的内行的程序和数据,运行时间、在存储器中的位置、占用的内存容

3、量等。存容量等。 线程线程 将一个进程划分为若干个独立的执行流,每一个执行流均称将一个进程划分为若干个独立的执行流,每一个执行流均称为一个线程。为一个线程。 (1)线程是)线程是CPU调度和分配的基本单位。调度和分配的基本单位。 (2)每个进程都有一个)每个进程都有一个主线程主线程。 (3)除了主线程以外,还可以给一个进程分配若干个子线程,)除了主线程以外,还可以给一个进程分配若干个子线程,从而达到多个任务并行执行的目的。从而达到多个任务并行执行的目的。4 42.2 进程管理(进程管理(Process类)类)1、Process类位于类位于System.Diagnostics命名空间下。命名空间

4、下。2、对本机(也叫本地计算机)、对本机(也叫本地计算机) (1)可以启动、终止某个进程)可以启动、终止某个进程 (2)可以查看进程相关信息,如)可以查看进程相关信息,如CPU利用率等利用率等 (3)可以查看进程工作状态)可以查看进程工作状态3、对远程计算机、对远程计算机 (1)可以查看远程计算机相关信息)可以查看远程计算机相关信息 (2)无法直接启动、终止远程计算机)无法直接启动、终止远程计算机4、在一个程序中处理其他的程序(例如调用其他、在一个程序中处理其他的程序(例如调用其他.exe文件、文件、 快捷方式等),实际上就是对进程进行管理。快捷方式等),实际上就是对进程进行管理。5 52.2

5、 进程管理(进程管理(Process类)类) Process类提供的静态方法类提供的静态方法6 62.2 进程管理(进程管理(Process类)类)5、Process类常用的属性和方法类常用的属性和方法-获取进程实例获取进程实例-uGetProcessById方法(静态方法):通过进程方法(静态方法):通过进程Id创建创建新的新的Process组件,并将其与本地计算机上的进程资源组件,并将其与本地计算机上的进程资源关联。关联。 GetProcessById最多只有一个最多只有一个Process实例。实例。uGetProcesses方法(静态方法):获取本机所有进程方法(静态方法):获取本机所有

6、进程uGetProcessesByName方法(静态方法):获取本机方法(静态方法):获取本机上特定名称的进程上特定名称的进程-获取及设置优先级获取及设置优先级-uBasePriority属性属性: 获取进程优先级(只读)获取进程优先级(只读)uPriorityClass 属性:设置或更改进程优先级属性:设置或更改进程优先级7 72.2 进程管理(进程管理(Process类)类)-进程进程ID及进程名及进程名-uId属性:获取关联进程的属性:获取关联进程的唯一标识符唯一标识符uProcessName属性:获取进程的名称,不包括路径和扩展名属性:获取进程的名称,不包括路径和扩展名 -进程其他信息

7、进程其他信息-uMachineName属性:获取关联进程正在其上运行的计算机名属性:获取关联进程正在其上运行的计算机名uMainModule属性:获取关联进程的主模块属性:获取关联进程的主模块uModules属性:获取由关联进程加载的模块属性:获取由关联进程加载的模块uTotalProcessorTime属性:获取进程的总的处理器时间属性:获取进程的总的处理器时间uStartTime属性:获取关联进程的启动时间属性:获取关联进程的启动时间uWorkingSet64属性:为进程分配的物理内存量(字节数)属性:为进程分配的物理内存量(字节数)8 81.2 Process类类-进程启动进程启动-uS

8、tart方法:启动进程资源并将其与方法:启动进程资源并将其与Process组件关联组件关联uStartInfo属性:获取或设置要传递给启动进程的文件名属性:获取或设置要传递给启动进程的文件名以及启动参数以及启动参数-进程终止进程终止-uKill方法:强制终止进程方法:强制终止进程uCloseMainWindow方法:关闭具有用户界面的进程方法:关闭具有用户界面的进程uClose方法:释放与此组件关联的所有资源方法:释放与此组件关联的所有资源uHasExited属性:指示关联进程是否已终止属性:指示关联进程是否已终止uWaitForExit方法:设置等待关联进程退出的时间,并在方法:设置等待关联

9、进程退出的时间,并在该段时间结束前或该进程退出前,阻止当前线程执行。该段时间结束前或该进程退出前,阻止当前线程执行。9 92.2.1 获取进程信息获取进程信息1、如何获取进程信息、如何获取进程信息(1)获取本地计算机的所有进程:)获取本地计算机的所有进程: Process myProcesses = Process.GetProcesses();(2)获取本地计算机上指定名称的进程:)获取本地计算机上指定名称的进程: Process myProcesses = Process.GetProcessesByName(进程名称进程名称); 注意:(注意:(a)进程名称不带扩展名。)进程名称不带扩展

10、名。 (b)可以是任何一个可执行文件)可以是任何一个可执行文件例如:例如: Process myProcesses = Process.GetProcessesByName (“notepad);10102.2.1 获取进程信息获取进程信息(续)(续)(3)获取远程计算机的所有进程:)获取远程计算机的所有进程: Process myProcesses = Process.GetProcesses (remoteMachineName); 例如:例如: Process myProcesses = Process.GetProcesses ();(4)获取远程计算机上指定名称

11、的进程:)获取远程计算机上指定名称的进程: Process myProcesses = Process.GetProcessesByName( 远程进程名称远程进程名称,remoteMachineName);1111程序举例程序举例【例例2-1】【例例2-1】观察本机运行的所有进程,并显示进程相关的信观察本机运行的所有进程,并显示进程相关的信息。息。 要求:要求: (1)用)用DataGridView显示所有进程信息显示所有进程信息 (2)鼠标单击)鼠标单击DataGridView某处时,判断单击的是否为某处时,判断单击的是否为行开头或者某个单元格,如果是,显示该行进程的详细行开头或者某个单元

12、格,如果是,显示该行进程的详细信息信息 (运行效果见下页图)(运行效果见下页图)12121.2.1 获取进程信息获取进程信息(续)(续)运行效果(运行效果(ProcessMonitor):):13132.2.2 启动和停止进程启动和停止进程1. 启动进程:启动进程:方法方法1:(1)创建一个)创建一个Process组件的实例,例如:组件的实例,例如: Process p = new Process();(2)设置其对应的)设置其对应的StartInfo属性,指定要运行的应用程序名以及属性,指定要运行的应用程序名以及传递的参数:传递的参数: p.StartInfo.FileName = 文件名文

13、件名; p.StartInfo.Arguments = 参数参数; 如果该进程带有图形用户界面,也可以指定图形用户界面的打如果该进程带有图形用户界面,也可以指定图形用户界面的打开方式。例如:开方式。例如: p.StartInfo.WindowStyle = ProcessWindowStyle.Normal;(3)调用该实例的)调用该实例的Start方法启动该进程。方法启动该进程。14142.2.2 启动和停止进程启动和停止进程1. 启动进程:启动进程: 方法方法2:直接调用直接调用Process类提供的类提供的Start静态方法启动进程。静态方法启动进程。进程启动举例:进程启动举例:1515

14、2.2.2 启动和停止进程(续)启动和停止进程(续)2. 停止进程停止进程 停止进程的方法有两种。停止进程的方法有两种。(1)如果进程有图形用户界面,调用)如果进程有图形用户界面,调用Process类提供的类提供的CloseMainWindow方法。方法。(2)如果进程没有用户界面,调用)如果进程没有用户界面,调用Process类提供的类提供的Kill方法。方法。 不论进程有没有图形用户界面,如果希望强行让其退不论进程有没有图形用户界面,如果希望强行让其退出,在权限允许的情况下,均可以调用出,在权限允许的情况下,均可以调用Kill方法终止该方法终止该进程。进程。 注意:若进程正要终止的同时调用

15、注意:若进程正要终止的同时调用Kill方法,可能会引方法,可能会引发异常,所以调用时最好使用发异常,所以调用时最好使用try/catch语句。语句。1616程序举例程序举例【例例2-2】【例例2-2】启动、停止和观察启动、停止和观察Notepad进程。进程。(StartStopProcess)要求:)要求:(1)用)用ListView显示显示“记事本记事本”进程信息。进程信息。(2)用)用Process类提供的实例方法启动进程。类提供的实例方法启动进程。(3)终止进程时,把所有)终止进程时,把所有“记事本记事本”进程全部终止。进程全部终止。1717扩充实验扩充实验【简易任务管理器开发】【简易任

16、务管理器开发】界面设计和开发要点:界面设计和开发要点: (1)ListView控件(列的定义、显示方式选择)控件(列的定义、显示方式选择) (2)NotifyIcon控件(最小化显示图标、界面还原显示)控件(最小化显示图标、界面还原显示) (3)Process类提供的属性和方法(进程启动、终止、进程相类提供的属性和方法(进程启动、终止、进程相关信息的获得)关信息的获得)1818项目中的应用:在程序中执行项目中的应用:在程序中执行sql文件文件说明:说明:osql.exe是是SQL Server提供的一个工具,可以利用该工提供的一个工具,可以利用该工具添加、删除数据库用户,修改用户登录密码,附加

17、、分离具添加、删除数据库用户,修改用户登录密码,附加、分离数据库等。对于通过程序管理数据库很有用。数据库等。对于通过程序管理数据库很有用。public void ExecuteSqlFile(string strFileName) Process SqlProcess=new Process(); SqlProcess.StartInfo.FileName=osql.exe; SqlProcess.StartInfo.Arguments=-U sa -P sa123 -d mydb -i+ strFileName; SqlProcess.StartInfo.WindowStyle= Proce

18、ssWindowStyle.Hidden; SqlProcess.Start(); SqlProcess.WaitForExit(); SqlProcess.Close(); 19192.3 线程管理(线程管理(Thread类)类) 2.3.1 前台线程与后台线程前台线程与后台线程 2.3.2 线程基本操作线程基本操作 2.3.3 Volatile关键字关键字 2.3.4 在一个线程中操作另一个线程的控件在一个线程中操作另一个线程的控件20202.3 线程管理(线程管理(Thread类)类) Thread类位于类位于System.Threading命名空间下。命名空间下。 Thread类是用于

19、创建和控制线程的类是用于创建和控制线程的,对线程的常用操作对线程的常用操作有:启动线程、终止线程、合并线程和让线程休眠等。有:启动线程、终止线程、合并线程和让线程休眠等。 Thread类提供的常用属性类提供的常用属性u IsAlive属性属性:获取一个值,该值指示当前线程的执行:获取一个值,该值指示当前线程的执行状态。如果此线程已启动并且尚未正常终止,则为状态。如果此线程已启动并且尚未正常终止,则为true;否则为否则为falseu IsBackground属性属性:获取或设置一个值,该值指示某获取或设置一个值,该值指示某个线程是否为后台线程。是后台线程或即将成为后台线个线程是否为后台线程。是

20、后台线程或即将成为后台线程,则为程,则为true;否则为;否则为false1. Priority属性:属性:获取或设置一个值,该值指示线程的调获取或设置一个值,该值指示线程的调度优先级度优先级21212.3 线程管理(线程管理(Thread类)(续)类)(续) Thread类提供的常用方法类提供的常用方法u Start方法方法:启动线程:启动线程u Join方法:方法:将指定的线程合并到当前线程中,并阻止当将指定的线程合并到当前线程中,并阻止当前线程执行,直到指定的线程终止或经过了指定的时间为前线程执行,直到指定的线程终止或经过了指定的时间为止止u Sleep方法:方法:将当前线程阻止指定的毫

21、秒数,零将当前线程阻止指定的毫秒数,零(0)表示应表示应挂起此线程以使其他等待线程能够执行挂起此线程以使其他等待线程能够执行1. Abort方法:方法:在调用此方法的线程上引发在调用此方法的线程上引发ThreadAbortException,以开始终止此线程的过程。调,以开始终止此线程的过程。调用此方法通常会终止线程用此方法通常会终止线程22222.3.1 前台线程与后台线程前台线程与后台线程一个线程要么是后台线程要么是前台线程。一个线程要么是后台线程要么是前台线程。后台线程与前台线程类似,区别是后台线程不会影响进后台线程与前台线程类似,区别是后台线程不会影响进程终止程终止。属于某个进程的所有

22、前台线程都终止后,公共。属于某个进程的所有前台线程都终止后,公共语言运行库就会结束该进程,而且所有属于该进程的后语言运行库就会结束该进程,而且所有属于该进程的后台线程也都会立即停止,而不管后台工作是否完成。台线程也都会立即停止,而不管后台工作是否完成。利用利用Thread对象的对象的IsBackground属性,可以设置或判属性,可以设置或判断一个线程是后台线程还是前台线程。断一个线程是后台线程还是前台线程。通过将某个线程的通过将某个线程的IsBackground属性设置为属性设置为true,使,使其变为后台线程。其变为后台线程。默认情况下,属于托管线程池的线程(即其默认情况下,属于托管线程池

23、的线程(即其IsThreadPoolThread属性为属性为true的线程)都是后台线的线程)都是后台线程,通过创建并启动新的程,通过创建并启动新的Thread对象而生成的线程都是对象而生成的线程都是前台线程。前台线程。23232.3.2 线程的基本操作线程的基本操作1.启动线程启动线程启动无参数线程的方法启动无参数线程的方法启动线程前,首先要创建一个线程。启动线程前,首先要创建一个线程。u第一步:创建无参数线程。例如:第一步:创建无参数线程。例如: Thread t1 = new Thread(方法名方法名);u第二步:调用第二步:调用Start方法启动线程。例如:方法启动线程。例如: t1

24、.Start(); /不带参数不带参数注意:调用注意:调用Start只是告诉系统启动该线程,但只是告诉系统启动该线程,但是系统并不一定会立即启动它。是系统并不一定会立即启动它。2424启动线程举例启动线程举例1执行无参数方法执行无参数方法/定义无参数的方法定义无参数的方法static void MethodA() for (int i = 0; i 10; i+) Console.WriteLine(i的当前值是的当前值是: + i); /创建创建线程线程并启动线程并启动线程Thread t1 = new Thread(new ThreadStart(MethodA);t1.Start();T

25、hread t2 = new Thread(MethodA);t2.Start();2525补充例题补充例题【E07-ThreadConsoleApplication】定义方法定义方法MethodAstatic void MethodA() for (int i = 0; i 10; i+) Console.WriteLine(i的当的当前值是前值是: + i); 定义方法定义方法MethodBstatic void MethodB() for (int j = 0; j 10; j+) Console.WriteLine(“j的当的当前值是前值是: + j); 在在Main方法内创建线程方法

26、内创建线程并启动线程并启动线程Thread t1 = new Thread(new ThreadStart(MethodA); t1.Start();Thread t2 = new Thread(new ThreadStart(MethodB); t2.Start();2626补充例题补充例题【E07-ThreadConsoleApplication】程序运行结果程序运行结果27272.3.2 线程的基本操作线程的基本操作1.启动线程启动线程启动有参数线程的方法启动有参数线程的方法 要求:必须传递一个要求:必须传递一个Object类型的参数类型的参数(1)传递单个参数)传递单个参数u创建带参数

27、线程(必须传递一个创建带参数线程(必须传递一个Object类型的参类型的参数):数): Thread t2 = new Thread(方法名方法名(Object obj);u调用调用Start方法启动线程,并将参数传过去。例如:方法启动线程,并将参数传过去。例如: t2.Start(“myClass”); /带参数带参数2828线程启动举例线程启动举例2传递单个参数传递单个参数源码见补充例题源码见补充例题【E07-ThreadConsoleApplication】/定义参数类型为定义参数类型为Object的方法的方法 static void MethodC(object obj)Console

28、.WriteLine(obj.ToString();/创建线程创建线程Thread t3 = new Thread(new ParameterizedThreadStart(MethodC);Thread t4 = new Thread(MethodC);/传递参数并启动线程传递参数并启动线程t3.Start(Thread T3);t4.Start(Thread T4);29292.3.2 线程的基本操作线程的基本操作1.启动线程启动线程传递多个参数传递多个参数 解决办法:将参数封装到一个类或结构中,然后传解决办法:将参数封装到一个类或结构中,然后传递该类或结构的实例。递该类或结构的实例。 具

29、体步骤:具体步骤: 定义封装类或结构;定义封装类或结构; 定义带定义带Object类型参数的方法;类型参数的方法; 初始化类或结构实例;初始化类或结构实例; 创建线程执行有参方法;创建线程执行有参方法; 启动线程传递参数;启动线程传递参数;3030线程启动举例线程启动举例3传递多个参数传递多个参数第一步:自定义类封装数据第一步:自定义类封装数据struct Data public int i; public string name; public string pwd; 第二步:定义参数类型为第二步:定义参数类型为Object类类型的方法型的方法/有参数的方法有参数的方法public void

30、 Method3(Object obj) Data data = (Data)obj;Console.WriteLine(方法方法3: + data.i + + data.pwd);第三步:实例化对象第三步:实例化对象 Data data = new Data(); data.i = 0; = lee; data.pwd = pwd;第四步:创建线程第四步:创建线程Thread myThread3 = new Thread(Method3);第五步:传递参数第五步:传递参数myThread3.Start(data);31312.3.2 线程的基本操作线程

31、的基本操作1.启动线程启动线程 考虑这种情况:需要向线程传递多个参数,但是线考虑这种情况:需要向线程传递多个参数,但是线程执行的方法是无参的,该如何实现?程执行的方法是无参的,该如何实现? 解决办法:将多个参数和线程要执行的方法封装到解决办法:将多个参数和线程要执行的方法封装到同一个类中,然后再初始化类的实例,创建线程执同一个类中,然后再初始化类的实例,创建线程执行类实例的无参实例方法,即可达到向无参数线程行类实例的无参实例方法,即可达到向无参数线程传递多个数据的目的。传递多个数据的目的。3232线程启动举例线程启动举例4向无参线程传递参数向无参线程传递参数1. 定义类封装数据和方法定义类封装

32、数据和方法class Person public string name; public string pwd; public void Method2() while (true) Thread.Sleep(1000);Debug.WriteLine(String.Format(方法方法2:参数:参数0 1, name, pwd); 2. 创建类的实例创建类的实例 Person person = new Person(); person. name = myName; person. pwd = mypwd;3. 创建线程执行无参的实例方创建线程执行无参的实例方法法myThread2 = n

33、ew Thread(person.Method2);4. 启动线程启动线程myThread2.Start();33332.3.2 线程的基本操作线程的基本操作2.终止线程终止线程 两种方法:两种方法: 事先设置一个事先设置一个布尔字段布尔字段,在其他线程中通过修改该,在其他线程中通过修改该布尔量的值作为传递给该线程是否需要终止的判断布尔量的值作为传递给该线程是否需要终止的判断条件,而在该线程中循环判断该布尔值,以确定是条件,而在该线程中循环判断该布尔值,以确定是否退出线程,这是结束线程比较好的方法,实际应否退出线程,这是结束线程比较好的方法,实际应用中一般使用这种方法。用中一般使用这种方法。

34、调用调用Thread类的类的Abort方法方法,该方法的最终效果是,该方法的最终效果是强行终止线程。强行终止线程。34342.3.2 线程的基本操作线程的基本操作3. 暂停线程暂停线程 在多线程应用程序中,有时候并不希望某一个线程继续在多线程应用程序中,有时候并不希望某一个线程继续执行,而是希望该线程暂停一段时间,这样,执行,而是希望该线程暂停一段时间,这样,CPU就会就会将其时间片中剩余的部分让给另一个线程。将其时间片中剩余的部分让给另一个线程。 调用调用Thread类的类的Sleep方法可以实现这个功能。例如:方法可以实现这个功能。例如: Thread.Sleep(1000); 这条语句的

35、功能是让当前线程暂停这条语句的功能是让当前线程暂停1000毫秒。毫秒。注意注意:Sleep方法是静态方法,暂停的是该语句所在的方法是静态方法,暂停的是该语句所在的线程,而不是其他线程。线程,而不是其他线程。35352.3.2 线程的基本操作线程的基本操作4.合并线程合并线程 Join方法用于把指定的线程合并到当前线程中,从而使其方法用于把指定的线程合并到当前线程中,从而使其变为一个单个的线程。变为一个单个的线程。 如果一个线程如果一个线程t1在执行的过程中需要等待另一个线程在执行的过程中需要等待另一个线程t2结束结束后才能继续执行,可以在后才能继续执行,可以在t1的代码块中调用的代码块中调用t

36、2的的join方法。方法。例如:例如: t2.Join(); 功能:功能:t1在执行到在执行到t2.Join()语句后,就处于暂停状态,直到语句后,就处于暂停状态,直到t2结束后才会继续执行。结束后才会继续执行。 为了避免为了避免t1一直等待,可以在调用一直等待,可以在调用t2的的Join方法的时候指方法的时候指定一个暂停时间,例如:定一个暂停时间,例如:t2.Join(100);36362.3.3 Volatile关键字关键字 volatile修饰符表示所声明的字段可以被多个并发执行的线修饰符表示所声明的字段可以被多个并发执行的线程修改。程修改。如果某个字段声明包含如果某个字段声明包含vol

37、atile关键字,则该字段关键字,则该字段将不再被编译器优化。这样可以确保该字段在任何时间呈现将不再被编译器优化。这样可以确保该字段在任何时间呈现的都是最新的值。的都是最新的值。 对于由多个线程访问的字段,而且该字段没有用对于由多个线程访问的字段,而且该字段没有用lock语句对语句对访问进行序列化,声明字段时应该使用访问进行序列化,声明字段时应该使用volatile修饰符。修饰符。 volatile修饰符只能包含在类或结构的字段声明中修饰符只能包含在类或结构的字段声明中,不能将不能将局部变量声明为局部变量声明为volatile。 在布尔型字段的声明中,添加在布尔型字段的声明中,添加volati

38、le修饰符的方法如下:修饰符的方法如下: public volatile bool shouldStop;37372.3.3 Volatile关键字关键字volatile修饰符可应用于以下类型修饰符可应用于以下类型:(1)引用类型。)引用类型。(2)指针类型(在不安全的上下文中)。)指针类型(在不安全的上下文中)。(3)整型整型,如,如sbyte、byte、short、ushort、int、uint、char、float和和bool。(4)具有整数基类型的枚举类型。)具有整数基类型的枚举类型。(5)已知为引用类型的泛型类型参数。)已知为引用类型的泛型类型参数。(6)IntPtr和和UIntPt

39、r。3838线程用法举例线程用法举例4线程的基本操作线程的基本操作 线程的操作(补充例题线程的操作(补充例题E01-WhyThread)39392.3.4 在一个线程中操作另一个线程的控件在一个线程中操作另一个线程的控件 默认情况下,在默认情况下,在Windows应用程序中,应用程序中,.NET Framework不允许在一个线程中直接操作另一个线程中的控件不允许在一个线程中直接操作另一个线程中的控件,这是,这是因为访问因为访问Windows窗体控件本质上不是线程安全的。窗体控件本质上不是线程安全的。 在应用程序中,如果创建某控件的线程之外的其他线程试在应用程序中,如果创建某控件的线程之外的其

40、他线程试图调用该控件,则系统会引发一个图调用该控件,则系统会引发一个InvalidOperationException异常。异常。 有两种办法可以解决这个问题:有两种办法可以解决这个问题: (1)使用委托()使用委托(delegate)操作另一个线程中的控件)操作另一个线程中的控件 (2)用)用BackgroundWorker组件在后台执行线程组件在后台执行线程40402.3.4 在一个线程中操作另一个线程的控件(续)在一个线程中操作另一个线程的控件(续) 利用委托调用另一个线程控件利用委托调用另一个线程控件:delegate void AppendStringDelegate(string

41、str);private void AppendString(string str) if(richTextBox1.InvokeRequired) AppendStringDelegate d = AppendString; richTextBox1.Invoke(d, str); else richTextBox1.Text += str; 4141程序举例【例程序举例【例2-3】【例例2-3】在在Class1类中声明两个方法类中声明两个方法Method1和和Method2,其中,其中Method1不停地输出字符不停地输出字符“a”,Method2不停地输出字符不停地输出字符“b”,在,在

42、Form1中启动线中启动线程执行程执行Method1和和Method2,并在,并在RichTextBox中中显示线程输出的字符。(显示线程输出的字符。(ThreadExample)42422.4 线程同步与线程池线程同步与线程池2.4.1 线程的优先级线程的优先级2.4.2 线程同步线程同步2.4.3 lock语句语句2.4.4 线程池线程池43432.4.1 线程的优先级线程的优先级 五个优先级,由高到低分别是:五个优先级,由高到低分别是:Highest、AboveNormal、Normal(默认)、(默认)、BelowNormal和和Lowest 可以使用下面的方法为其赋予较高的优先级:可

43、以使用下面的方法为其赋予较高的优先级: Thread t = new Thread(MethodName); t.priority = ThreadPriority.AboveNormal; 通过设置线程的优先级可以改变线程的执行顺序,所设通过设置线程的优先级可以改变线程的执行顺序,所设置的优先级仅仅适用于这些线程所属的进程。置的优先级仅仅适用于这些线程所属的进程。 注意:注意: 当把某线程的优先级设置为当把某线程的优先级设置为Highest时,系统正在运行的时,系统正在运行的其他线程都会终止,所以使用这个优先级别时要特别小其他线程都会终止,所以使用这个优先级别时要特别小心。心。44442.4

44、.2 线程同步线程同步同步同步 指多个线程之间存在先后执行顺序的关联关系指多个线程之间存在先后执行顺序的关联关系。哪些资源需要同步哪些资源需要同步u系统资源(如通信端口)系统资源(如通信端口)u多个进程所共享的资源(如文件句柄)多个进程所共享的资源(如文件句柄)u由多个线程访问的单个应用程序域的资源(如全由多个线程访问的单个应用程序域的资源(如全局、静态和实例字段)局、静态和实例字段)45452.4.2 线程同步线程同步为什么要同步为什么要同步 当两个线程当两个线程t1和和t2有相同的优先级,并且同时在系有相同的优先级,并且同时在系统上运行时,如果先把时间片分给统上运行时,如果先把时间片分给t

45、1使用,它在结构使用,它在结构s1中(该结构中有多个变量)写入某些值,但如果中(该结构中有多个变量)写入某些值,但如果在时间片用完时它仍没有完成写入,这时由于时间片在时间片用完时它仍没有完成写入,这时由于时间片已经分给已经分给t2使用,而使用,而t2又恰好要尝试读取该结构的值,又恰好要尝试读取该结构的值,此时读出的就不是正确的值。这种情况下,如果使用此时读出的就不是正确的值。这种情况下,如果使用同步仅允许一个线程使用同步仅允许一个线程使用s1,在该线程完成对,在该线程完成对s1的的写入工作后再让写入工作后再让t2读取这个结构值,就可以避免出现读取这个结构值,就可以避免出现此类错误。此类错误。4

46、6462.4.2 线程同步线程同步解决方法解决方法:uSystem.Threading命名空间提供了多个用于同步命名空间提供了多个用于同步线程的类这些类包括线程的类这些类包括Mutex、Monitor、Interlocked和和AutoResetEvent。其中:。其中:uMutex类锁定多线程间同步调用,即锁定调用端。类锁定多线程间同步调用,即锁定调用端。uMonitor、Lock语句锁定数据或者被调用的函数,语句锁定数据或者被调用的函数,即锁定被调用端。即锁定被调用端。u在实际应用中在实际应用中经常使用经常使用lock语句语句完成线程同步。完成线程同步。该语句简化了编程的复杂性,使程序看起

47、来既清晰该语句简化了编程的复杂性,使程序看起来既清晰又简洁又简洁47472.4.3 lock语句语句lock语句的功能语句的功能u lock语句可以有效地实现同步,即将代码段语句可以有效地实现同步,即将代码段(语句块)标记为临界区。(语句块)标记为临界区。u lock语句能确保当一个线程位于代码的语句能确保当一个线程位于代码的临界区临界区(可以理解为对某些资源进行操作的一段代码)(可以理解为对某些资源进行操作的一段代码)时,另一个线程不进入临界区。如果其他线程试时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码段,则它将一直等待(即被阻图进入锁定的代码段,则它将一直等待(即被阻塞),直

48、到锁定的对象被释放以后才能进入临界塞),直到锁定的对象被释放以后才能进入临界区。区。48482.4.3 lock语句(续)语句(续)lock语句的用法语句的用法 首先利用首先利用lock语句锁定某一个对象,然后执行代码语句锁定某一个对象,然后执行代码段中的语句,等代码段中的语句执行完毕后,再释段中的语句,等代码段中的语句执行完毕后,再释放该对象。放该对象。 例如:例如:private Object obj = new Object();lock(obj) /临界区中的代码临界区中的代码49492.4.3 lock语句(续)语句(续)使用使用lock语句应注意的问题语句应注意的问题:u锁定的对象

49、名(上面代码中的锁定的对象名(上面代码中的obj)一般声)一般声明为明为Object类型,不要将其声明为值类型。类型,不要将其声明为值类型。u锁定的对象名不能将其声明为锁定的对象名不能将其声明为public,只,只能为能为privateu临界区中的代码一般不宜太多。临界区中的代码一般不宜太多。5050程序举例【例程序举例【例2-4】【例例2-4】lock语句用法举例:多线程随机取款。语句用法举例:多线程随机取款。 (相当于某公司派多人在多台自动取款机上同时取款)(相当于某公司派多人在多台自动取款机上同时取款)运行效果:(运行效果:(lockExample)正确的运行结果正确的运行结果 错误的运

50、行结果错误的运行结果51512.4.4 线程池线程池背景:背景: 1)无限制的创建线程消耗系统资源)无限制的创建线程消耗系统资源 2)创建线程、回收线程均需要时间)创建线程、回收线程均需要时间线程池的默认大小:每个可用处理器线程池的默认大小:每个可用处理器25个线程。个线程。 每个进程都有一个线程池。每个进程都有一个线程池。为什么要用线程池?为什么要用线程池?u 降低系统开销降低系统开销u 可以重用资源,使应用程序可以避免为每个任务可以重用资源,使应用程序可以避免为每个任务创建新线程引起的资源和时间消耗。创建新线程引起的资源和时间消耗。52522.4.4 线程池(续)线程池(续)线程池:线程池

51、:是在是在后台执行后台执行多个任务的线程集合。多个任务的线程集合。 1)最大线程数最大线程数限制。如果所有线程都繁忙,则额外限制。如果所有线程都繁忙,则额外的任务将放入等待队列中,直到有线程可用时才能够的任务将放入等待队列中,直到有线程可用时才能够得到处理。得到处理。 2)最小线程数最小线程数=创建线程池时应立即启动的数目创建线程池时应立即启动的数目 3)一旦池中的某个线程完成任务,它将返回到等待)一旦池中的某个线程完成任务,它将返回到等待线程队列中,等待被再次使用。这种重用使应用程序线程队列中,等待被再次使用。这种重用使应用程序可以避免为每个任务创建新线程引起的资源和时间消可以避免为每个任务

52、创建新线程引起的资源和时间消耗。耗。 4)一项工作任务被加入到线程池的队列中,就不能)一项工作任务被加入到线程池的队列中,就不能取消该任务,直到该任务完成。取消该任务,直到该任务完成。53532.4.4 线程池(续)线程池(续)什么情况下才使用线程池?什么情况下才使用线程池?u后台执行,后台执行,而且不同线程没有优先级区别而且不同线程没有优先级区别u适用于需要多个线程而实际执行时间又不多的场适用于需要多个线程而实际执行时间又不多的场合合u没有导致线程长时间被阻塞的任务没有导致线程长时间被阻塞的任务(对于可能长对于可能长时间被阻塞的任务,应该创建单独的线程处理,时间被阻塞的任务,应该创建单独的线

53、程处理,不应该使用线程池),这是因为线程池具有最大不应该使用线程池),这是因为线程池具有最大线程数限制,大量阻塞的线程池线程可能会阻止线程数限制,大量阻塞的线程池线程可能会阻止任务启动任务启动 54542.4.4 线程池(续)线程池(续)ThreadPool类类位于位于System.Threading命名空间下。命名空间下。ThreadPool提供了对线程池的操作(静态方法),提供了对线程池的操作(静态方法),例如:发送工作项、处理异步例如:发送工作项、处理异步I/O、设置线程数目等、设置线程数目等ThreadPool是一个是一个静态类静态类托管线程池中的线程为后台线程,即它们的托管线程池中的

54、线程为后台线程,即它们的IsBackground属性为属性为true。这意味着在所有的前台。这意味着在所有的前台线程都已退出后,线程都已退出后,ThreadPool线程也会自动退出线程也会自动退出55552.4.4 线程池(续)线程池(续) GetAvailableThreads方法:检索由方法:检索由GetMaxThreads返回的返回的线程池线程的最大数目和当前活动数目之间的差值线程池线程的最大数目和当前活动数目之间的差值 GetMaxThreads方法:检索可以同时处于活动状态的线程池方法:检索可以同时处于活动状态的线程池请求的数目。所有大于此数目的请求将保持排队状态,直到请求的数目。所

55、有大于此数目的请求将保持排队状态,直到线程池线程变为可用线程池线程变为可用 GetMinThreads方法:检索线程池在新请求预测中维护的空方法:检索线程池在新请求预测中维护的空闲线程数闲线程数 SetMaxThreads方法:可以同时处于活动状态的线程池的请方法:可以同时处于活动状态的线程池的请求数目。所有大于此数目的请求将保持排队状态,直到线程求数目。所有大于此数目的请求将保持排队状态,直到线程池线程变为可用。池线程变为可用。 SetMinThreads方法方法:设置线程池在新请求预测中维护的空设置线程池在新请求预测中维护的空闲线程数闲线程数56562.4.4 线程池(续)线程池(续) Q

56、ueueUserWorkItem方法功能:方法功能:u功能:请求线程池处理一个任务或者工作项功能:请求线程池处理一个任务或者工作项u运行时线程池会自动为每一个任务创建线程并且在任运行时线程池会自动为每一个任务创建线程并且在任务结束时释放线程。务结束时释放线程。u语法语法:带一个带一个WaitCallback委托的参数,这个参数包装委托的参数,这个参数包装了要完成的任务了要完成的任务 Public static bool QueueUserWorkItem ( WaitCallback callBack, object state) Public static bool QueueUserWorkItem ( WaitCallback callBack)参数参数:state:包含方法所用数据的对象包含方法所用数据的对象callBack: System.Threading.WaitCallback,它表示要,它表示要执行的方法执行的方法57572.4.4 线程池

温馨提示

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

评论

0/150

提交评论