zhouqijie

多线程

进程和线程

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)来实现线程同步。

线程安全

  1. 尽可能避免使用共享状态。(静态字段、全局变量、同一对象字段等都是共享的)
  2. 使用互斥锁来线程同步。(即上述lock关键字或者Monitor类)

线程状态

CRE:参考操作系统教材中的五态模型。

当线程阻塞或者解除阻塞时,操作系统将进行上下文切换,开销约1毫秒或者2毫秒。

阻塞和忙等待有一些细微差别。如果时条件很快得到满足(几毫秒),建议使用忙等待来避免上下文切换的开销延迟。
忙等待示例:while(currentTime < targetTime)

同步上下文(SynchronizationContext)

把一些数据的所有权从一个线程交给另一个线程。

当运行在UI线程时可以通过它来获得同步上下文。
捕获该属性让你可以在稍后得时候从worker线程向ui线程发送数据。

上下文对象的Post方法把委托Marshal给UI线程。(相当于控件得BeginInvoke方法)
上下文对象还有个Send方法。(相当于控件的Invoke方法)

CRE:WinForms初始化同步上下文之前(即Application.Run()调用前),返回的当前上下文为null。

(END)