多线程编程,自由编程(free-threaded)
概念:调度(scheduling)、竞态条件(race condition)、线程关联(thread affinity)、死锁(deadlock)、临界区(critical section)同步对象、线程池(thread pool)、计时器(timer)
1.为什么使用线程
线程使程序代码复杂化,但是获得较好的吞吐能力throughput和响应速度responsiveness
挂起hang:及时响应用户接口的维护
2.理解底层机制
多任务multitasking:同一时间段内运行多个进程
多线程multithreading:每个进程能够同时执行多个任务
.NET Framework引入了一个概念上的轻型进程--应用程序域(Application Domain.AppDomain)
1)Windows CE
一个进程:主线程(primary thread或main thread)
次线程(secondary thread)或工作线程(worker thread)
操作系统由时间片段轮转(round-robin)方式运行线程
线程都有一其自身的堆栈、一个CPU寄存器副本和一片线程局部存储区(Thread-Local Storage,TLS)
线程运行持续一段预置的时间长度----线程拥有的“时间总量(thread quantum)”,或时间片段(context switch)
线程调度----线程优先级
.NET Compact Framework程序的默认线程
2) System.Threading
鼠标右键“解析”
Synchronization Fuctions:msdn2.microsoft.com/en-us/library/aa302340.aspx#win32map-aynchronizationfunctions
内存屏障memory barriers
静态方法MemoryBarrier:msdn2.microsoft.com/en-us/library/system.threading.memorybarrier.aspx
新类型 Semaphore www.daniel,oth.com/Blog/2005/01/semaphore.html
EventWaitHandle www.danielmoth.com/Blog/2005/01/eventwaithandle.html
3.及时响应用户接口的维护
1)消息泵message pump
消息----消息队列(消息泵)----.NET事件----主线程
2)耗时的任务
用一个工作线程来及时响应UI
3)演示示例
4)不理想的解决方案
Refresh方法
DoEvents方案:处理队列中所有的消息,继续执行DoEvents后面的代码(会产生重入代码reentrant code的问题)
5)使用线程来解决问题
System.Windows.Forms.Timer----轮询(polling)技术 (不完美)
Thread.Join(不推荐用在主线程上)
UI线程的规范:尽在创建UI元素的线程上操作它们----Windows对象具有线程亲和性(thread affinity),
强调:不要在工作线程中操作UI控件
让方法知道它们是由主线程、工作线程调用的,通过检查Control.InvokeRequired属性
Control.Invoke
死锁(deadlock):主线程被阻塞,等待工作线程的结束,其间,工作线程也等待主线程处理由Invoke方法发出的自定义Windows消息。相互等待,结果都不继续执行。
解决:工作线程完成任务后,让主线程得到通知,以便主线程可以将最终的结果更新到UI上
6)BackgroundWorker组件
相关示例:www.danielmoth.com/Blog/2004/12/backgroundworker-sample.html
4.线程活动的同步与数据访问
线程的弊端:死锁、竞态条件(race condition)
1)竞态条件
多个线程同时访问同一块数据
Ildasm.exe反汇编
说明:高级语言写成的代码在运行时会被拆成多行代码,调度程序(scheduler)可能在任意位置进行上下文切换(context switching)
原子性(atomic)
2)监视器monitor
临界区(critical regions):保护并发访问的代码区,每次只能有一个线程进入的代码区域
3)线程安全thread safe
线程安全:可以安全的在多个线程中被调用的方法
框架方法----实例方法
集合类
4)再论死锁
精心设计:彻底掌握线程在各处的执行情况,线程之间能够通信
5) ManualResetEvent
线程间的通信与协议
AutoResetEvent
Mutex(互斥锁),.NET Compact Framework中不能使用
5. ThreadPool线程池
需要指定一个委托,这个委托还要接受一个object类型的状态
6.理解线程与程序的关闭
主窗体退出标志着程序的结束(程序没有创建任何线程)----当所有后台(foreground)线程都推出后,程序才会结束
1)后台线程
前台线程----显示创建的线程
后台线程----来自ThreadPool或由框架创建的线程
除非用户操作,则使用的线程都应为后台线程
设置为后台线程的方法:线程被启动前,IsBackground属性设置为true,为其命名,这两个属性纳入构造过程
平台调用服务PInvoke
2)线程的终止
Abort方法强行退出(不推荐)
声明工作线程和主线程都可见的布尔变量
7.使用.NET计时器
System.Threading.Timer由来自ThreadPool线程触发
注意:保留一个计时器对象的引用,符合垃圾回收的条件
使用完后,释放
参数