多线程
进程和线程
CRE:进程是拥有资源的基本单位。进程的资源被线程共享,线程不拥有资源。
CRE:单核计算机上,操作系统位每个线程分配时间片来实现并行。(并发不是真的并行)
前台线程和后台线程
通过Thread类新建的线程都是前台线程。当所有前台线程关闭时,后台线程也会被直接终止,不会抛出异常。
托管线程池内的线程都是后台线程。只要有一个前台线程未退出,进程就不会终止。
应用程序必须完成所有前台线程才可以退出。所有后台线程在应用程序退出时都会自动结束。
设置isBackground=true
来设置为后台线程。
创建线程
只需要声明线程,并提供起点方法委托即可。
Thread t = new Thread(new ThreadStart(Foo));//Thread类创建
ThreadPool.QueueUserWorkItem(Foo, args); //线程池创建
线程外
try/catch
无法捕获线程内的异常。异常处理逻辑应该放在线程的委托方法中。
挂起和恢复线程
尽量少用,可能会死锁。
挂起之前.NET运行再执行几个指令,目的是安全挂起。
Suspend()
挂起
Resume()
恢复
休眠线程
Sleep(int)
休眠毫秒数
Sleep(TimeSpan)
重载
Sleep(0)
放弃当前时间片,让系统调度其他线程,如果没有则再次继续执行本线程。类似Yield(),但是Yield()只给同一处理器的其他线程。
终止线程
线程的结束条件,构造时传入的委托执行完毕。
线程的IsAlive属性指示是否已结束。
Abort()
永久地停止托管线程。调用时,CLR在目标线程中引发ThreadAbortException。目标线程可以捕获该异常。
Join()
阻止调用线程,直到某个线程终止时为止。(调用后主线程会阻塞等待某线程执行完毕才继续)
线程优先级(Priority)
决定了相对其他线程所占的执行时间。
提升线程优先级可能会造成其他线程饥饿。
线程同步
同步是指某一时刻只有一个线程可以访问资源。主动放弃代码/资源所有权时其他线程才可以访问这些资源。
可以使用lock语句来设置锁定,lock语句是由Monitor类实现的。
还可以用互斥体(Mutex)对象或者信号量(semaphore)来实现线程同步。
线程安全
- 尽可能避免使用共享状态。(静态字段、全局变量、同一对象字段等都是共享的)
- 使用互斥锁来线程同步。(即上述lock关键字或者Monitor类)
线程状态
CRE:参考操作系统教材中的五态模型。
- 上下文切换
当线程阻塞或者解除阻塞时,操作系统将进行上下文切换,开销约1毫秒或者2毫秒。
- 阻塞和忙等待
阻塞和忙等待有一些细微差别。如果时条件很快得到满足(几毫秒),建议使用忙等待来避免上下文切换的开销延迟。
忙等待示例:while(currentTime < targetTime)
。
同步上下文(SynchronizationContext)
- Thread Marshaling
把一些数据的所有权从一个线程交给另一个线程。
- SynchronizationContext.Current
当运行在UI线程时可以通过它来获得同步上下文。
捕获该属性让你可以在稍后得时候从worker线程向ui线程发送数据。
上下文对象的Post
方法把委托Marshal给UI线程。(相当于控件得BeginInvoke方法)
上下文对象还有个Send
方法。(相当于控件的Invoke方法)
CRE:WinForms初始化同步上下文之前(即Application.Run()调用前),返回的当前上下文为null。
(END)