CLR线程池
虽然CLR通过System.Threading名称空间提供了对Windows线程API的封装,但直接创建和销毁线程严重影响性能。过多的线程不仅浪费内存,而且会造成频繁的CPU上下文切换,更重要的是线程大部分时间都处于无所事事的状态,浪费宝贵的CPU时间。其次多线程非常容易引发滥用,特别是那些没什么多线程基础的程序员,为了所谓的“性能”无脑使用线程,即使在一些商业软件中这种现象也比比皆是。为了减少这种现象,CLR提供了原生的线程池支持。对于每个CLR,线程池线程将被所有运行中的托管程序集共享。
线程池调度
CLR的初始线程池为空,每当托管程序请求使用线程池线程或执行异步任务,CLR会将程序请求的任务添加到线程池的任务记录,并分配给一个线程执行。如果没有可用线程,则创建一个新线程。与直接使用Thread相比,线程池线程完成任务后并不会销毁,而是进入线程池等待新任务。CLR线程池使用启发式的线程分配策略,当有大量任务请求时会创建较多的线程,而空闲时则销毁多余的线程以节省内存。
执行上下文
CLR中每个线程都与一个执行上下文相关联,其中包括运行权限、用户标识以及区域设置等等信息,每当线程被创建时,会从被创建的线程复制一份执行上下文。对于不需要执行上下文信息的线程来说,这一操作明显影响性能。因此CLR提供了ExecutionContext类来对执行上下文进行控制。
1 2 3 4 5 6 7 8 9 10 11 12 13
   | public static void main() { 	 	CallContext.LogicalSetData("User","Admin"); 	 	ThreadingPool.QueueUserWorkItem((state)=>Console.WriteLine(CallContext.LogicalGetData("User").ToString())); 	 	ExecutionContext.SuppressFlow(); 	 	ThreadingPool.QueueUserWorkItem((state)=>Console.WriteLine(CallContext.LogicalGetData("User").ToString())); 	 	ExecutionContext.RestoreFlow(); }
   | 
 
取消与超时
线程池比Thread类更好的一点是支持协作式取消以及任务超时,只需要将一个CancellatinTokenSource对象与任务相关联,即可方便的取消任务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
   | public static void main() { 	CancellationTokenSource cts = new CancellationTokenSource(); 	ThreadPool.QueueUserWorkItem(state=>Count(cts.Token,1000000)); 	Console.WriteLine("回车键取消..."); 	Console.ReadLine(); 	cts.Cancel(); 	 	 }
  private void Count(CancellationToken token, Int32 count) { 	for(int i=0;i<=count;i++) 	{ 		if(token.IsCancellationRequested) 		{ 			Console.WriteLine("已取消");	 			break; 		} 		Console.WriteLine(i); 		Thread.Sleep(200); 	} }
   | 
 
CancellationTokenSource类
以下是CTS的.NET源代码节选:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
   | public class CancellationTokenSource: IDisposable {	 	 	private volatile ManualResetEvent m_kernelEvent; 	 	private volatile SparselyPopulatedArray<CancellationCallbackInfo>[] m_registeredCallbacksLists; 	 	private const int CANNOT_BE_CANCELED = 0;     private const int NOT_CANCELED = 1;     private const int NOTIFYING = 2;     private const int NOTIFYINGCOMPLETE = 3; 	private volatile int m_state; 	 	public CancellationToken token{get}; 	public bool IsCancellationRequested 	{ 		get{return m_state>=NOTIFING;} 	}
  	 	internal WaitHandle WaitHandle 	{ 		if (m_kernelEvent != null)         	return m_kernelEvent;                              ManualResetEvent mre = new ManualResetEvent(false);         if (Interlocked.CompareExchange(ref m_kernelEvent, mre, null) != null)         {             	((IDisposable)mre).Dispose();         }  		         if (IsCancellationRequested)         	m_kernelEvent.Set();           return m_kernelEvent; 	}
  	 	public Cancel(bool throwOnFirstException) 	{ 		ThrowIfDisposed(); 		NotifyCancellation(throwOnFirstException); 	}
  	private void NotifyCancellation(bool throwOnFirstException) 	{ 		if (IsCancellationRequested) 			return;
  		if (Interlocked.CompareExchange(ref m_state, NOTIFYING, NOT_CANCELED) == NOT_CANCELED) 		{ 			 			Timer timer = m_timer; 			if(timer != null) timer.Dispose(); 		 			if (m_kernelEvent != null) 				m_kernelEvent.Set(); 			 			ExecuteCallbackHandlers(throwOnFirstException); 		} 	} 	 	public static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token1, CancellationToken token2) 	{ 		 	}
  	private CancellationTokenRegistration Register(Action<Object> callback, Object state, bool useSynchronizationContext, bool useExecutionContext)     { 		 		 	} }
 
  public struct CancellationToken { 	 	private CancellationTokenSource m_source; 	public bool IsCancellationRequested 	{get 	 	public WaitHandle WaitHandle 	{get 	 	public CancellationTokenRegistration Register(Action callback, bool useSyncContext) }
   |