Welcome

首页 / 软件开发 / C# / C#并行编程概述:线程同步原语

C#并行编程概述:线程同步原语2014-10-12 未知 背景

有时候必须访问变量、实例、方法、属性或者结构体,而这些并没有准备好用于并发访问,或者有时候需要执行部分代码,而这些代码必须单独运行,这是不得不通过将任务分解的方式让它们独立运行。

当任务和线程要访问共享的数据和资源的时候,您必须添加显示的同步,或者使用原子操作或锁。

之前的.NET Framework提供了昂贵的锁机制以及遗留的多线程模型,新的数据结构允许细粒度的并发和并行化,并且降低一定必要的开销,这些数据结构称为轻量级同步原语。

这些数据结构在关键场合下能够提供更好的性能,因为它们能够避免昂贵的锁机制,如果在等待时间不短的情况下使用它们,这些原语会增加额外的开销。

如果您需要特定的执行顺序,可以通过添加显示同步来实现。

同步原语

.NET Framework 4在现在的System.Threading命名空间中提供了6个同步原语,通过这个命名空间可以访问遗留的线程类、类型和枚举,还提供了新的基于任务的编程模型及特定情形紧密相关的数据结构

Barrier 使多个任务能够采用并行方式依据某种算法在多个阶段中协同工作 通过屏障

CountdownEvent 表示在计数变为0时处于有信号状态的同步基元 通过信号机制

ManualResetEventSlim 允许很多任务等待直到另一个任务手工发出事件句柄,当预计等待时间很短的时候,ManualResetEventSlim 的性能比对应的重量级ManualResetEvent的性能要高。通过信号机制

SemaphoreSlim 限制对可同时访问资源或资源池的线程数,比对应的Semaphore性能要高 通过信号机制

SpinLock 提供一个相互排斥锁基元,在该基元中,尝试获得锁的线程将在重复检查的循环中等待,直至该锁变为可用为止。

SpinWait 提供对基于自旋的等待的支持。

通过屏障同步并发任务 Barrier

当在需要一组任务并行地运行一连串的阶段,但是每一个阶段都要等待其他任务完成前一阶段之后才能开始时,您可以通过使用Barrier类的实例来同步这一类协同工作,通过屏障

下面贴代码方便大家理解,如有问题,请指正,详情见注释:

class Program{private static Task[] _CookTasks { get; set; }private static Barrier _barrier { get; set; }/*获取当前计算机处理器数*/private static int _particpants = Environment.ProcessorCount;/*coder:释迦苦僧 *代码中 展示煮饭的步骤 1.打水2.淘米 3.放入锅中 4.盖上锅盖 5.生火煮饭*/static void Main(string[] args){Console.WriteLine("定义{0}个人煮饭3次", _particpants);_CookTasks = new Task[_particpants];_barrier = new Barrier(_particpants, (barrier) =>{Console.WriteLine("当前阶段:{0}", barrier.CurrentPhaseNumber);});Stopwatch swTask1 = new Stopwatch();swTask1.Start();/*定义N个人*/for (int cook_person = 0; cook_person < _particpants; cook_person++){_CookTasks[cook_person] = Task.Factory.StartNew((num) =>{int index = Convert.ToInt32(num);/*每个人煮3次饭*/for (int cook_count = 0; cook_count < 3; cook_count++){CookStepTask1(index, cook_count);CookStepTask2(index, cook_count);CookStepTask3(index, cook_count);CookStepTask4(index, cook_count);CookStepTask5(index, cook_count);}}, cook_person);}/*ContinueWhenAll 提供一组任务完成后 延续方法*/var finalTask = Task.Factory.ContinueWhenAll(_CookTasks, (tasks) =>{/*等待任务完成*/Task.WaitAll(_CookTasks);swTask1.Stop();Console.WriteLine("采用并发 {1}个人煮3次饭耗时:{0}", swTask1.ElapsedMilliseconds, _particpants);/*释放资源*/_barrier.Dispose();});Thread.Sleep(4000);Stopwatch swTask = new Stopwatch();swTask.Start();/*定义N个人*/for (int cook_person = 0; cook_person < _particpants; cook_person++){/*每个人煮3次饭*/for (int cook_count = 0; cook_count < 3; cook_count++){CookStep1(cook_person, cook_count); CookStep2(cook_person, cook_count); CookStep3(cook_person, cook_count); CookStep4(cook_person, cook_count); CookStep5(cook_person, cook_count);}}swTask.Stop();Console.WriteLine("不采用并发 {1}个人煮3次饭耗时:{0}", swTask.ElapsedMilliseconds, _particpants);Thread.Sleep(2000);Console.ReadLine();}/*1.打水*/private static void CookStepTask1(int pesron_index, int index){Console.WriteLine("{0} 第{1}次 打水... 耗时2分钟", pesron_index, index);Thread.Sleep(200);/*存在线程暂停 所以需要将 _barrier.SignalAndWait();放在方法中 */_barrier.SignalAndWait();}/*2.淘米*/private static void CookStepTask2(int pesron_index, int index){Console.WriteLine("{0} 第{1}次 淘米... 耗时3分钟", pesron_index, index);Thread.Sleep(300);/*存在线程暂停 所以需要将 _barrier.SignalAndWait();放在方法中 */_barrier.SignalAndWait();}/*3.放入锅中*/private static void CookStepTask3(int pesron_index, int index){Console.WriteLine("{0} 第{1}次 放入锅中... 耗时1分钟", pesron_index, index);Thread.Sleep(100);/*存在线程暂停 所以需要将 _barrier.SignalAndWait();放在方法中 */_barrier.SignalAndWait();}/*4.盖上锅盖*/private static void CookStepTask4(int pesron_index, int index){Console.WriteLine("{0} 第{1}次 盖上锅盖... 耗时1分钟", pesron_index, index);Thread.Sleep(100);/*存在线程暂停 所以需要将 _barrier.SignalAndWait();放在方法中 */_barrier.SignalAndWait();}/*5.生火煮饭*/private static void CookStepTask5(int pesron_index, int index){Console.WriteLine("{0} 第{1}次生火煮饭... 耗时30分钟", pesron_index, index);Thread.Sleep(500);/*存在线程暂停 所以需要将 _barrier.SignalAndWait();放在方法中 */_barrier.SignalAndWait();}/*1.打水*/private static void CookStep1(int pesron_index, int index){Console.WriteLine("{0} 第{1}次 打水... 耗时2分钟", pesron_index, index);Thread.Sleep(200);}/*2.淘米*/private static void CookStep2(int pesron_index, int index){Console.WriteLine("{0} 第{1}次 淘米... 耗时3分钟", pesron_index, index);Thread.Sleep(300);}/*3.放入锅中*/private static void CookStep3(int pesron_index, int index){Console.WriteLine("{0} 第{1}次 放入锅中... 耗时1分钟", pesron_index, index);Thread.Sleep(100);}/*4.盖上锅盖*/private static void CookStep4(int pesron_index, int index){Console.WriteLine("{0} 第{1}次 盖上锅盖... 耗时1分钟", pesron_index, index);Thread.Sleep(100);}/*5.生火煮饭*/private static void CookStep5(int pesron_index, int index){Console.WriteLine("{0} 第{1}次生火煮饭... 耗时30分钟", pesron_index, index);Thread.Sleep(500);}}class Product{public string Name { get; set; }public string Category { get; set; }public int SellPrice { get; set; }}
如代码所示,在串行代码中,虽然任务是有序进行,但是等待的时间很长,因为只是在一个处理器下进行处理,如下图所示:

URL:http://www.bianceng.cn/Programming/csharp/201410/45755.htm