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

下载本文档

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

文档简介

多线程编程基础 主要内容 1线程概述2 NET对多线程的支持3一个多线程程序4线程的优先级5线程的同步6多线程的自动管理7应用实例 1线程概述 进程 是应用程序的一个运行例程 是应用程序的一次动态执行过程 线程 是进程中的一个执行单元 是操作系统分配CPU时间的基本单元 Windows是一个支持多线程的系统 一个进程可以包含若干个线程 多线程的概念 多线程 在同一时间执行多个任务的功能 称为多线程或自由线程 多线程的优点 可以同时完成多个任务 可以使程序的响应速度更快 可以让占用大量处理时间的任务或当前没有进行处理的任务定期将处理时间让给别的任务 可以随时停止任务 可以设置每个任务的优先级以优化程序性能 主要缺点 对资源的共享访问可能造成冲突 对共享资源的访问进行同步或控制 程序的整体运行速度减慢等等 何时需要用多线程 许多经常执行的操作可能需要很长的执行时间 图像下载Web服务调用文件下载和上载 包括点对点应用程序 复杂的本地计算数据库事务本地磁盘访问 相对于内存访问来说其速度很慢 此类操作可能导致用户界面在操作运行时挂起 长时间得不到响应 2 NET对多线程的支持 在 NET程序设计中 线程是使用Thread类 或Timer类 线程计数器 ThreadPool类 线程池 来处理的 这些类在System Threading命名空间中 usingSystem Threading Thread类 实现线程的主要方法 一个Thread实例管理一个线程 即执行序列 通过简单实例化一个Thread对象 就可以创建一个线程 然后通过Thread对象提供的方法对线程进行管理 Timer类 适用于间隔性的完成任务 ThreadPool 适用于多个小的线程 Thread类的主要属性 1 CurrentThread 获取当前正在运行的线程 2 Name 获取或设置线程的名称 3 Priority 获取或设置线程的优先级 4 TreadState 获取或设置线程的当前状态 5 IsBackground 指示线程是否为后台线程 6 IsAlive 指示当前线程的执行状态 7 CurrentContext 获取线程其中执行的当前上下文 Thread类的主要方法 1 Abort 终止线程 2 GetDomain 返回当前线程正在其中运行的当前域 3 Interrupt 中断处于WaitSleepJoin线程状态的线程 4 Join 阻塞调用线程 直到某个线程终止时为止 5 ResetAbort 取消为当前线程请求的Abort6 Resume 继续已挂起的线程 7 Sleep 将当前线程阻塞指定的毫秒数 8 Start 启动线程 9 Suspend 挂起线程 Thread类中线程的状态 由Thread类的TreadState属性来确定 Abort AbortRequested BackGround Running Stopped StopRequested Suspended SuspendRequsted Unstarted WaitSleepJoin 线程的建立与启动 新建一个线程的过程 只需将其声明并为其提供线程起始点处的方法委托 再用Thread Start 方法启动该线程 1 声明 Threada 2 实例化a newThread newThreadStart b 其中 b为新建过程中执行的过程名 3 调用Thread Start 方法启动该线程a Start 例1 线程的建立和启动 usingSystem usingSystem Threading publicclassA publicvoidff 线程启动时调用此方法 Console WriteLine A ff 方法在另一个线程上运行 Thread Sleep 3000 将线程阻塞一定时间Console WriteLine 终止工作线程调用此实例方法 publicstaticvoidgg Console WriteLine A gg 方法在另一个线程上运行 Thread Sleep 5000 将线程阻塞一定时间Console WriteLine 终止工作线程调用此静态方法 publicclassB publicstaticvoidMain Console WriteLine 线程简单示例 Aa newA Threads1 newThread newThreadStart a ff s1 Start Console WriteLine 启动新线程ff 方法后 被Main 线程调用 Threads2 newThread newThreadStart A gg s2 Start Console WriteLine 启动新线程gg 方法后 被Main 线程调用 Console ReadLine 线程的挂起 恢复与终止 线程的挂起 或暂停 1 调用Thread Sleep 方法将线程挂起 注 Sleep 方法指定的时间以毫秒为单位 2 调用s1 Suspend 方法将线程挂起区别 前者为静态方法 并且使线程立即暂停一定时间 后者为实例方法 不会使线程立即停止执行 直到线程到达安全点之后 它才将该线程暂停 线程的恢复与终止调用Resume 方法将线程恢复 调用Abort 方法将线程终止 其他与操作线程相关的方法 Join 使一个线程等待另一个线程停止 或等待一定的时间Interrupt 中断处于JoinWaitSleep线程状态的线程 实现模拟抽奖程序 单击滚动号码 在另一个线程中遍历号码单击抽奖 将当前号码作为中奖号码 不用多线程 在文本框中滚动数字 publicvoidRollNum inti 0 liNum AddliNum AddliNum AddliNum AddliNum AddliNum AddliNum AddliNum Add循环while i liNum Count i 0 txtNum Text liNum i ToString i 用户界面得不到响应 为什么 将号码的滚动放在另一个线程中执行 privatevoidbtnRoll Click objectsender EventArgse 定义一个线程rollThread newThread newThreadStart RollNum 开启线程rollThread Start btnRoll Enabled false btnLottery Enabled true 运行期错误 线程间操作无效 从不是创建控件 txtNum 的线程访问它 在C 应用程序中 第一个线程总是Main 方法 后续的线程由应用程序在内部启动 即应用程序可以创建和启动新的线程 WindowsForm程序的线程可分为 UI线程 是form程序运行的主线程 它负责界面的创建 更新等与界面直接有关的工作 其他与消息循环无关的线程叫工作线程 解密 解密 Windows窗体使用单线程单元 STA 模型 因为它基于本机Win32窗口 而Win32窗口从本质上而言是单元线程 STA模型意味着可以在任何线程上创建窗口 但窗口一旦创建后就不能切换线程 并且对它的所有函数调用都必须在其创建线程上发生 除了Windows窗体之外 NETFramework中的类使用自由线程模型 STA模型要求需从控件的非创建线程调用的控件上的任何方法必须被封送到 在其上执行 该控件的创建线程 解决方案 Windows窗体中的控件被绑定到特定的线程 不具备线程安全性 因此 如果从另一个线程调用控件的方法 那么必须使用控件的一个Invoke方法来将调用封送到适当的线程 基类Control为此提供了若干方法 Invoke BeginInvoke和EndInvoke Invoke生成同步方法调用 BeginInvoke生成异步方法调用 Invoke BeginInvoke的使用 定义与函数功能对应的委托将参数以及函数名通过委托实例传递给Invoke BeginInvoke delegatevoidShowTextDelegate stringtext publicvoidRollNum inti 0 初始化号码集合while i liNum Count i 0 this txtNum Invoke newShowTextDelegate ShowText liNum i ToString i 抽奖按钮完成的工作 停止工作线程 停止号码滚动 并将当前号码显示 privatevoidbtnLottery Click objectsender EventArgse rollThread Suspend 执行到安全点后挂起rollThread Resume 恢复 关闭线程rollThread Abort btnRoll Enabled true btnLottery Enabled false MessageBox Show 恭喜号码 txtNum Text 中奖 信息提示 偏差的解决 原因 线程之间有 时差 解决 Thread CurrentThread Join 1000 使用线程能极大地提升用户体验度 但是作为开发者应该注意到 线程的开销是很大的 线程的空间开销 线程内核对象 ThreadKernelObject 每个线程都会创建一个这样的对象 它主要包含线程上下文信息 在32位系统中 它所占用的内存在700字节左右 线程环境块 ThreadEnvironmentBlock TEB包括线程的异常处理链 32位系统中占用4KB内存 用户模式栈 UserModeStack 即线程栈 线程栈用于保存方法的参数 局部变量和返回值 每个线程栈占用1024KB的内存 要用完这些内存很简单 写一个不能结束的递归方法 让方法参数和返回值不停地消耗内存 很快就会发生OutOfMemoryException 内核模式栈 KernelModeStack 当调用操作系统的内核模式函数时 系统会将函数参数从用户模式栈复制到内核模式栈 在32位系统中 内核模式栈会占用12KB内存 线程的时间开销 线程创建的时候 系统相继初始化以上这些内存空间 CLR会调用所有加载DLL的DLLMain方法 并传递连接标志 线程终止的时候 也会调用DLL的DLLMain方法 并传递分离标志 线程上下文切换 一个系统中会加载很多的进程 而一个进程又包含若干个线程 但是一个CPU在任何时候都只能有一个线程在执行 为了让每个线程看上去都在运行 系统会不断地切换 线程上下文 每个线程大概得到几十毫秒的执行时间片 然后就会切换到下一个线程了 这个过程大概又分为以下5个步骤 步骤1进入内核模式 步骤2将上下文信息 主要是一些CPU寄存器信息 保存到正在执行的线程内核对象上 步骤3系统获取一个Spinlock 并确定下一个要执行的线程 然后释放Spinlock 如果下一个线程不在同一个进程内 则需要进行虚拟地址交换 步骤4从将被执行的线程内核对象上载入上下文信息 步骤5离开内核模式 替代方案 使用线程池 BackgroundWorker组件BackGroundWorker组件在内部使用了线程池的技术 还在UI线程和工作线程间增加进度显示 取消等功能 基于事件的异步模式概述 异步模式 通过在另一个线程上执行耗时的操作 可以让用户界面 UI 提高响应能力 是一种同时执行多项任务 但仍能响应用户交互的应用程序实施的一种使用多线程的设计方案System Threading命名空间提供了创建高性能多线程应用程序所必需的所有工具需要有丰富的使用多线程软件工程的经验 基于事件的异步模式的优点 在后台 执行耗时任务 例如下载和数据库操作 但不会中断您的应用程序 同时执行多个操作 每个操作完成时都会接到通知 等待资源变得可用 但不会停止 挂起 您的应用程序 使用熟悉的事件和委托模型与挂起的异步操作通信 比较 计算Fibonacci数 非异步模式用户界面得不到及时响应 BackgroundWorker组件 在不同于应用程序的主用户界面线程的另一线程上异步 在后台 执行耗时的操作 使窗体或控件能够异步运行操作原理 调用RunWorkerAsync方法 执行该组件在后台执行的耗时的辅助方法在辅助方法以异步方式运行的同时 调用主线程继续正常运行 后台方法运行完毕 BackgroundWorker激发RunWorkerCompleted事件 可选择包含操作结果 向调用线程发出警报 三次参数传递 参数传递1 将RunWorkerAsync Object 中的Object传递到DoWork事件的DoWorkEventArgs Argument 由于在这里只有一个参数可以传递 所以在实际应用往往封装一个类 将整个实例化的类作为RunWorkerAsync的Object进行传递 UI Worker 参数传递2 将程序运行进度传递给ProgressChanged事件 一般用于更新进度条或者日志信息 Worker UI 参数传递3 在DoWork事件代码执行结束之前 将后台线程产生的结果数据赋给DoWorkEventArgs Result 以便在RunWorkerCompleted事件中取得后台线程产生的结果 Worker UI 步骤 创建一个基于Windows的应用程序在窗体中创建一个BackgroundWorker在按钮事件中调用BackgroundWorker RunWorkerAsync 以触发DoWork事件 开始执行后台耗时过程添加异步事件处理程序添加进度报告和取消支持 实现异步事件处理程序 在 属性 窗口中单击 事件 按钮 双击DoWork和RunWorkerCompleted事件来创建事件处理程序在窗体中创建一个称为ComputeFibonacci的新方法 此方法完成实际的工作 并在后台运行 在DoWork事件处理程序中 添加对ComputeFibonacci方法的调用 将DoWorkEventArgs的Argument属性作为ComputeFibonacci的第一个参数 示例 对于0 299999间的每个值I 计算Math Sqrt i Math Sin i i i 的累加和 要求支持进度报告和取消操作 Step1 启动后台运算 privatevoidbtnCalc Click objectsender EventArgse intnum int Parse this textBox1 Text this backgroundWorker1 RunWorkerAsync num this btnCalc Enabled false this btnCancel Enabled true 设置属性WorkerSupportsCancellation true WorkerReportsProgress true 发送后台操作指令 Step2 编写后台代码 privatevoidbackgroundWorker1 DoWork objectsender DoWorkEventArgse intnum int e Argument longtotal 0 intpercent 0 for inti 1 ipercent percent backgroundWorker1 ReportProgress percent 报告进度 e Result total Step3 更改进度信息 报告结果 privatevoidbackgroundWorker1 ProgressChanged objectsender ProgressChangedEventArgse this progressBar1 Value e ProgressPercentage privatevoidbackgroundWorker1 RunWorkerCompleted objectsender RunWorkerCompletedEventArgse if e Cancelled MessageBox Show e Result ToString elseMessageBox Show Iscanceled Step4 取消支持 privatevoidbtnCancel Click objectsender EventArgse this backgroundWorker1 CancelAsync 修改DoWork中相应代码 在每次循环前判断用户有无取消for inti 1 ipercent percent backgroundWorker1 ReportProgress percent else e Cancel true 真正中断后台线程 更多例子 Fibonacci数列计算大目录的复制 privatevoidbackgroundWorker1 DoWork objectsender DoWorkEventArgse 获取后台线程引用 BackgroundWorkerworker senderasBackgroundWorker 将计算的结果也就是Fibonacci n 赋给 DoWorkEventArgs参数的Result属性 该值可在 RunWorkerCompleted事件参数中读取 以在界面显示e Result ComputeFibonacci int e Argument worker e privatevoidstartAsyncButton Click objectsender EventArgse resultLabel Text String Empty this numericUpDown1 Enabled false this startAsyncButton Enabled false this cancelAsyncButton Enabled true GetthevaluefromtheUpDowncontrol numberToCompute int numericUpDown1 Value Resetthevariableforpercentagetracking highestPercentageReached 0 Starttheasynchronousoperation backgroundWorker1 RunWorkerAsync numberToCompute 触发DoWork事件 添加进度报告和取消支持 由于异步操作将会花费很长的时间 因此通常希望向用户报告进度并允许用户取消操作 BackgroundWorker类提供一种在后台操作进行时允许发送进度消息的事件 实现进度报告实现取消支持 实现进度报告 在 属性 窗口中 将backgroundWorker1的WorkerReportsProgress和WorkerSupportsCancellation属性设置为true 在FibonacciCalculator窗体中声明两个变量 用来跟踪进度privateintnumberToCompute 0 privateinthighestPercentageReached 0 为ProgressChanged事件添加事件处理程序 更新ProgressBar voidbackgroundWorker1 ProgressChanged objectsender ProgressChangedEven

温馨提示

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

评论

0/150

提交评论