《C#并行编程高级教程》-第五章:协调数据结构
本章主要讲如何同步任务已经多线程中共享变量,应用到的是一些经典的同步原语,.NET 4.0新引进的轻量级协调数据结构。
轻量级同步原语
.NET 4.0 System.Threading中提供了6个轻量级的同步原语:
Barrier:容许多个任务同步他们不同阶段上的并发工作;
CountdownEvent:简化了fork和join情形,表示非常轻量级的原语,每一个任务完成后都会减少计数,直到减少到0再开始制定的任务。
ManualResetEventSlim:容许很多任务等待直到另一个任务手工发出事件句柄。如果预计等待时间很短应该使用此类,较其对应重量级类:ManualResetEvent的性能要高。
SemaphoreSlim:限制能够并发访问某个资源或资源池的任务个数。对应重量级:Semaphore
SpinLock:容许一个任务自旋直到获得一个互斥锁,以保证一次只有一个任务能够访问所定的变量、对象或者区域。与此类似的有System.Threading.Monitor。SpinLock是一个struct,要是使用大量的锁,而且希望能够最小化对象的分配,那么使用SpinLock可以减少内存的需求以及垃圾回收的压力。
SpinWait:容许一个任务执行基于自旋的等待,直到指定的条件得到满足。可以使用SpinWait指定一个等待时间,在等待时间之前是自旋,若超过了指定时间还没有满足条件,那么进入基于内核的等待,也就是“基于自旋的等待->(超过指定时间)->基于内核的等待”。
Barrier
需要运行一组任务,每个任务都有一连串的阶段,而且每个阶段的运行都要等到其他所有任务的前一阶段运行完毕才能开始,这样就可以考虑Barrier来同步这类工作。可以在多个阶段中使用同一个Barrier实例。
int participantes=4; // the member of taking part in
Task[] tasks=new Task[participantes];
int timeout=2000; //if wait 2s,quit wait and go on
var cts=new System.Threading.CancellationTokenSource();
vat ct=cts.Token;
//构造函数
Barrier barrier=new Barrier(participantes,(_barrier)=>
{ //dosomething.....//阶段后操作代码 } );
for(int i=0;i<participantes;i++)
{
tasks[i]=Task.Factory.StartNew( (num)=>{
//dosomething:Phase1
try //扑捉阶段后操作代码中的异常,可以对每个SignalAndWait的都使用
{
barrier.SignalAndWait(timeout);
}
catch(BarrierPostPhaseException bppex)
{ //do somenthing.........}
//dosomething:Phase2
barrier.SignalAndWait(timeout);
//dosomething:Phase3
barrier.SignalAndWait(timeout);
//more phase....
},i,ct);
}
var finalTask=Task.Factory.ContinueWhenAll(tasks, (alltasks)=>{
//do so