多线程与UI的用法区别_第1页
多线程与UI的用法区别_第2页
多线程与UI的用法区别_第3页
多线程与UI的用法区别_第4页
多线程与UI的用法区别_第5页
已阅读5页,还剩47页未读 继续免费阅读

下载本文档

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

文档简介

1、 1 线程概述2 .NET对多线程的支持3 一个多线程程序4 线程的优先级 5 线程的同步 6 多线程的自动管理 7 应用实例 进程:是应用程序的一个运行例程,是应用程序的一次动态执行过程。线程:是进程中的一个执行单元;是操作系统分配CPU时间的基本单元。Windows是一个支持多线程的系统。一个进程可以包含若干个线程。多线程:在同一时间执行多个任务的功能,称为多线程或自由线程。多线程的优点:可以同时完成多个任务;可以使程序的响应速度更快;可以让占用大量处理时间的任务或当前没有进行处理的任务定期将处理时间让给别的任务;可以随时停止任务;可以设置每个任务的优先级以优化程序性能。主要缺点:对资源的

2、共享访问可能造成冲突(对共享资源的访问进行同步或控制) ;程序的整体运行速度减慢等等。 许多经常执行的操作可能需要很长的执行时间。 u图像下载uWeb 服务调用u文件下载和上载(包括点对点应用程序)u复杂的本地计算u数据库事务u本地磁盘访问(相对于内存访问来说其速度很慢) 此类操作可能导致用户界面在操作运行时挂起,长时间得不到响应 在.NET程序设计中,线程是使用Thread类(或Timer类(线程计数器)、ThreadPool类(线程池)来处理的,这些类在System.Threading命名空间中:using System.Threading;Thread类:(实现线程的主要方法)一个Thr

3、ead实例管理一个线程,即执行序列。通过简单实例化一个Thread对象,就可以创建一个线程,然后通过Thread对象提供的方法对线程进行管理。 Timer类:适用于间隔性的完成任务。ThreadPool:适用于多个小的线程。1、CurrentThread:获取当前正在运行的线程。2、Name:获取或设置线程的名称。3、Priority:获取或设置线程的优先级。4、TreadState:获取或设置线程的当前状态。5、IsBackground:指示线程是否为后台线程。6、IsAlive:指示当前线程的执行状态。7、CurrentContext:获取线程其中执行的当前上下文。1、Abort:终止线程

4、。2、GetDomain:返回当前线程正在其中运行的当前域。3、Interrupt:中断处于WaitSleepJoin线程状态的线程。4、Join:阻塞调用线程,直到某个线程终止时为止。5、ResetAbort:取消为当前线程请求的Abort6、Resume:继续已挂起的线程。7、Sleep:将当前线程阻塞指定的毫秒数。8、Start:启动线程。9、Suspend;挂起线程。由Thread类的TreadState属性来确定:Abort、AbortRequested、BackGround、Running、Stopped、StopRequested、Suspended、SuspendRequste

5、d、Unstarted、WaitSleepJoin新建一个线程的过程:只需将其声明并为其提供线程起始点处的方法委托,再用Thread.Start()方法启动该线程(1)声明:Thread a;(2)实例化a=new Thread(new ThreadStart(b);其中,b为新建过程中执行的过程名。(3)调用Thread.Start()方法启动该线程a.Start();using System;using System.Threading;public class A public void ff()/线程启动时调用此方法Console.WriteLine(A.ff()方法在另一个线程上运行

6、!);Thread.Sleep(3000);/将线程阻塞一定时间Console.WriteLine(终止工作线程调用此实例方法!); public static void gg()Console.WriteLine(A.gg()方法在另一个线程上运行!);Thread.Sleep(5000);/将线程阻塞一定时间Console.WriteLine(终止工作线程调用此静态方法!); public class B public static void Main()Console.WriteLine(*线程简单示例!*);A a=new A();Thread s1=new Thread(new Th

7、readStart(a.ff);s1.Start();Console.WriteLine(启动新线程ff()方法后,被Main()线程调用!);Thread s2=new Thread(new ThreadStart(A.gg);s2.Start();Console.WriteLine(启动新线程gg()方法后,被Main()线程调用!);Console.ReadLine();线程的挂起(或暂停)线程的挂起(或暂停)(1)调用Thread.Sleep()方法将线程挂起。注:Sleep()方法指定的时间以毫秒为单位。(2)调用s1.Suspend() 方法将线程挂起区别:前者为静态方法,并且使线

8、程立即暂停一定时间;后者为实例方法,不会使线程立即停止执行,直到线程到达安全点之后,它才将该线程暂停。线程的恢复与终止线程的恢复与终止调用Resume()方法将线程恢复;调用Abort()方法将线程终止;Join():使一个线程等待另一个线程停止,或等待一定的时间Interrupt():中断处于JoinWaitSleep线程状态的线程。 单击滚动号码,在另一个线程中遍历号码 单击抽奖,将当前号码作为中奖号码 / / 在文本框中滚动数字在文本框中滚动数字 / public void RollNum() int i = 0; liNum.Add; liNum.Add(18

9、676768762); liNum.Add; liNum.Add; liNum.Add; liNum.Add; liNum.Add; liNum.Add; /循环循环 while (i = liNum.Count) i = 0; txtNum.Text = liNumi.ToString(); i+; 用户界面得不到响应.为什么? private void btnRoll_Click(object sender, EventArgs e)

10、/定义一个线程定义一个线程 rollThread = new Thread(new ThreadStart(RollNum); /开启线程开启线程 rollThread.Start(); btnRoll.Enabled = false; btnLottery.Enabled = true; 运行期错误:线程间操作无效: 从不是创建控件“txtNum”的线程访问它 在C#应用程序中,第一个线程总是Main()方法。后续的线程由应用程序在内部启动,即应用程序可以创建和启动新的线程。 Windows Form程序的线程可分为:uUI线程:是form程序运行的主线程,它负责界面的创建,更新等与界面直接

11、有关的工作。u其他与消息循环无关的线程叫工作线程 Windows 窗体使用单线程单元 (STA) 模型,因为它基于本机 Win32 窗口,而 Win32 窗口从本质上而言是单元线程。 STA 模型意味着可以在任何线程上创建窗口,但窗口一旦创建后就不能切换线程,并且对它的所有函数调用都必须在其创建线程上发生。除了 Windows 窗体之外,.NET Framework 中的类使用自由线程模型。 STA 模型要求需从控件的非创建线程调用的控件上的任何方法必须被封送到(在其上执行)该控件的创建线程。 Windows 窗体中的控件被绑定到特定的线程,不具备线程安全性。因此,如果从另一个线程调用控件的方

12、法,那么必须使用控件的一个 Invoke 方法来将调用封送到适当的线程。 基类 Control 为此提供了若干方法(Invoke、BeginInvoke和 EndInvoke)。uInvoke 生成同步方法调用;uBeginInvoke 生成异步方法调用。 定义与函数功能对应的委托 将参数以及函数名通过委托实例传递给Invoke/BeginInvokedelegate void ShowTextDelegate(string text);public void RollNum() int i = 0; /初始化号码集合 while (i = liNum.Count) i = 0; this.t

13、xtNum.Invoke(new ShowTextDelegate(ShowText),liNumi.ToString(); i+; 停止工作线程,停止号码滚动,并将当前号码显示private void btnLottery_Click(object sender, EventArgs e) rollThread.Suspend();/执行到安全点后挂起执行到安全点后挂起 rollThread.Resume;/恢复恢复 /关闭线程关闭线程 rollThread.Abort(); btnRoll.Enabled = true; btnLottery.Enabled = false; Messag

14、eBox.Show(“恭喜号码恭喜号码 + txtNum.Text + 中奖中奖, 信息提示信息提示); 原因:线程之间有”时差” 解决:u Thread.CurrentThread.Join(1000); 使用线程能极大地提升用户体验度,但是作为开发者应该注意到,线程的开销是很大的 线程内核对象(Thread Kernel Object)。每个线程都会创建一个这样的对象,它主要包含线程上下文信息,在32位系统中,它所占用的内存在700字节左右。 线程环境块(Thread Environment Block)。TEB包括线程的异常处理链,32位系统中占用4KB内存。 用户模式栈(User Mo

15、de Stack),即线程栈。线程栈用于保存方法的参数、局部变量和返回值。每个线程栈占用1024KB的内存。要用完这些内存很简单,写一个不能结束的递归方法,让方法参数和返回值不停地消耗内存,很快就会发生OutOfMemoryException。 内核模式栈(Kernel Mode Stack)。当调用操作系统的内核模式函数时,系统会将函数参数从用户模式栈复制到内核模式栈。在32位系统中,内核模式栈会占用12KB内存。 线程创建的时候,系统相继初始化以上这些内存空间。 CLR会调用所有加载DLL的DLLMain方法,并传递连接标志(线程终止的时候,也会调用DLL的DLLMain方法,并传递分离标

16、志)。 线程上下文切换。一个系统中会加载很多的进程,而一个进程又包含若干个线程。但是一个CPU在任何时候都只能有一个线程在执行。为了让每个线程看上去都在运行,系统会不断地切换“线程上下文”:每个线程大概得到几十毫秒的执行时间片,然后就会切换到下一个线程了。这个过程大概又分为以下5个步骤:u步骤1进入内核模式。u步骤2将上下文信息(主要是一些CPU 寄存器信息)保存到正在执行的线程内核对象上。u步骤3系统获取一个 Spinlock,并确定下一个要执行的线程,然后释放 Spinlock。如果下一个线程不在同一个进程内,则需要进行虚拟地址交换。u步骤4从将被执行的线程内核对象上载入上下文信息。u步骤

17、5离开内核模式。 使用线程池/BackgroundWorker组件 BackGroundWorker组件在内部使用了线程池的技术,还在UI线程和工作线程间增加进度显示、取消等功能 通过在另一个线程上执行耗时的操作,可以让执行耗时的操作,可以让用户界面用户界面 (UI) 提高响应能力。提高响应能力。 是一种同时执行多项任务、但仍能响应用户交是一种同时执行多项任务、但仍能响应用户交互的应用程序实施的一种使用多线程的设计方互的应用程序实施的一种使用多线程的设计方案案 System.Threading 命名空间提供了创建高性命名空间提供了创建高性能多线程应用程序所必需的所有工具能多线程应用程序所必需的

18、所有工具 需要有丰富的使用多线程需要有丰富的使用多线程软件工程的经验 在后台”执行耗时任务(例如下载和数据库操作),但不会中断您的应用程序。 同时执行多个操作,每个操作完成时都会接到通知。 等待资源变得可用,但不会停止(“挂起”)您的应用程序。 使用熟悉的事件和委托模型与挂起的异步操作通信。 非异步模式用户界面得不到及时响应 在不同于应用程序的主用户界面线程的另一线程上异步(“在后台”)执行耗时的操作。使窗体或控件能够异步运行操作 原理:u调用 RunWorkerAsync 方法,执行该组件在后台执行的耗时的辅助方法u在辅助方法以异步方式运行的同时,调用主线程继续正常运行。u后台方法运行完毕,

19、BackgroundWorker 激发 RunWorkerCompleted 事件(可选择包含操作结果)向调用线程发出警报。 参数传递1:将RunWorkerAsync(Object)中的Object传递到DoWork事件的DoWorkEventArgs.Argument,由于在这里只有一个参数可以传递,所以在实际应用往往封装一个类,将整个实例化的类作为RunWorkerAsync的Object进行传递;(UIWorker) 参数传递2:将程序运行进度传递给ProgressChanged事件,一般用于更新进度条或者日志信息; (WorkerUI) 参数传递3:在DoWork事件代码执行结束之前

20、,将后台线程产生的结果数据赋给DoWorkEventArgs.Result,以便在RunWorkerCompleted事件中取得后台线程产生的结果。 (WorkerUI) 创建一个基于 Windows 的应用程序 在窗体中创建一个 BackgroundWorker 在按钮事件中调用BackgroundWorker. RunWorkerAsync()以触发DoWork事件,开始执行后台耗时过程 添加异步事件处理程序 添加进度报告和取消支持 在“属性”窗口中单击“事件”按钮。双击 DoWork 和 RunWorkerCompleted 事件来创建事件处理程序 在窗体中创建一个称为 ComputeF

21、ibonacci 的新方法。此方法完成实际的工作,并在后台运行。 在 DoWork 事件处理程序中,添加对 ComputeFibonacci 方法的调用。将 DoWorkEventArgs 的 Argument 属性作为 ComputeFibonacci 的第一个参数。 对于0299999间的每个值I,计算Math.Sqrt(i) + Math.Sin(i * i * i)的累加和,要求支持进度报告和取消操作private void btnCalc_Click(object sender, EventArgs e) int num=int.Parse(this.textBox1.Text);

22、this.backgroundWorker1.RunWorkerAsync(num); this.btnCalc.Enabled = false; this.btnCancel.Enabled = true; 设置属性uWorkerSupportsCancellation= true;uWorkerReportsProgress = true; 发送后台操作指令private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) int num = (int)e.Argument; long total = 0; int

23、 percent = 0; for (int i = 1; i percent) percent+; backgroundWorker1.ReportProgress(percent);/报告进度报告进度 e.Result = total; private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) gressBar1.Value = e.ProgressPercentage; private void backgroundWorker1_RunWorkerC

24、ompleted(object sender, RunWorkerCompletedEventArgs e) if (!e.Cancelled) MessageBox.Show(e.Result.ToString(); else MessageBox.Show(Is canceled!); private void btnCancel_Click(object sender, EventArgs e) this.backgroundWorker1.CancelAsync(); /修改DoWork中相应代码.在每次循环前判断用户有无取消 for (int i = 1; i percent) pe

25、rcent+; backgroundWorker1.ReportProgress(percent); else e.Cancel = true;/真正中断后台线程真正中断后台线程 Fibonacci数列计算 大目录的复制private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) / 获取后台线程引用. BackgroundWorker worker = sender as BackgroundWorker; / 将计算的结果也就是Fibonacci(n)赋给 / DoWorkEventArgs参数的Result

26、属性,该值可在 / RunWorkerCompleted事件参数中读取,以在界面显示 e.Result = ComputeFibonacci(int)e.Argument, worker, e); private void startAsyncButton_Click(object sender, EventArgs e) resultLabel.Text = String.Empty; this.numericUpDown1.Enabled = false; this.startAsyncButton.Enabled = false; this.cancelAsyncButton.Enabl

27、ed = true; / Get the value from the UpDown control. numberToCompute = (int)numericUpDown1.Value; / Reset the variable for percentage tracking. highestPercentageReached = 0; / Start the asynchronous operation. backgroundWorker1.RunWorkerAsync(numberToCompute); 触发DoWork事件 由于异步操作将会花费很长的时间,因此通常希望向用户报告进度

28、并允许用户取消操作。BackgroundWorker 类提供一种在后台操作进行时允许发送进度消息的事件。 实现进度报告实现进度报告 实现取消支持实现取消支持 在“属性”窗口中,将backgroundWorker1的 WorkerReportsProgress 和 WorkerSupportsCancellation 属性设置为 true。 在 FibonacciCalculator 窗体中声明两个变量,用来跟踪进度 private int numberToCompute = 0; private int highestPercentageReached = 0; 为 ProgressChanged 事件添加事件处理程序,更新 ProgressBar。void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) gressBar1.Value = e.ProgressPercentage; 在 cancelAsyncButton 控件的 Click 事件处理程序中,

温馨提示

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

评论

0/150

提交评论