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");
//获取上下文信息--打印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();
//超时自动取消
//cts.CancelAfter(1000);
}

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;
//一个类似链表的内部类,记录CTS取消时调用的回调函数
private volatile SparselyPopulatedArray<CancellationCallbackInfo>[] m_registeredCallbacksLists;
//CTS状态
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;
//通过结构体CT暴露方法(轻量化便于传递参数?)
public CancellationToken token{get};
public bool IsCancellationRequested
{
get{return m_state>=NOTIFING;}
}

//WaitHandle是对WaitForSingleObject API函数的包装
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();
//执行注册到CTS的回调函数
ExecuteCallbackHandlers(throwOnFirstException);
}
}
//创建联合CTS,其中任意CTS取消则该CTS即取消
public static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token1, CancellationToken token2)
{
//方法内部调用Register注册回调
}

private CancellationTokenRegistration Register(Action<Object> callback, Object state, bool useSynchronizationContext, bool useExecutionContext)
{
//注册到CTS取消时要调用的回调函数
//可调用返回值的Dispose方法取消回调
}
}

//轻量化,便于作为参数传递
public struct CancellationToken
{
//对CTS的引用
private CancellationTokenSource m_source;
public bool IsCancellationRequested
{get//暴露CTS的属性}

public WaitHandle WaitHandle
{get//暴露CTS的WaitHandle}
//暴露CTS方法
public CancellationTokenRegistration Register(Action callback, bool useSyncContext)
}

 评论




载入天数...载入时分秒...  |  总访问量为
Powered by Github and MarkdownPad 2

--------------------------- 别拉了,我是有底线的>_< ---------------------------