大学IT网 - 最懂大学生的IT学习网站! QQ资料交流群:367606806
当前位置:大学IT网 > C#技巧 > C#并行编程-线程同步原语

C#并行编程-线程同步原语(1)

关键词:并行编程线程同步C#  阅读(2329) 赞(19)

[摘要]本文是对C#并行编程-线程同步原语的讲解,对学习C#编程技术有所帮助,与大家分享。

菜鸟学习并行编程,参考《C#并行编程高级教程.PDF》,如有错误,欢迎指正。

背景

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

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

之前的.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; }
    }
«上一页1234下一页»


相关评论