现在的位置: 首页 > 综合 > 正文

[深夜原创]C# Monitor通知机制的一个有趣的实例

2013年01月03日 ⁄ 综合 ⁄ 共 1793字 ⁄ 字号 评论关闭

主要使用Monitor类,对一个对象进行等待和通知的操作

        static void Main(string[] args)
        {
            //Task启动等待对象
            object taskStartSyncRoot = new object();

            //多线程等待对象
            object syncRoot = new object();

            //多线程全部进入等待状态对象
            object parallelStartSyncRoot = new object();

            lock (taskStartSyncRoot)
            {
                Task.Factory.StartNew(() =>
                {
                    lock (parallelStartSyncRoot)
                    {
                        lock (taskStartSyncRoot)
                        {
                            //通知Task已经启动完毕
                            Monitor.Pulse(taskStartSyncRoot);
                        }

                        Console.WriteLine("Wait all parallel task started.");

                        //等待所有并行任务已经进行等待状态,并释放parallelStartSyncRoot锁
                        Monitor.Wait(parallelStartSyncRoot);

                        lock (syncRoot)
                        {
                            //通知所有并行任务syncRoot已经释放
                            Monitor.PulseAll(syncRoot);
                            Console.WriteLine("All syncRoot waiter notified.");
                        }
                    }
                });

                //等待Task启动完毕,并释放taskStartSyncRoot对象锁
                Monitor.Wait(taskStartSyncRoot);
            }

            //并行等待任务计数器,当该计数器为10时,则通知所有并行任务已经进入等待状态
            int counter = 0;

            Parallel.For(0, 10, (i) =>
            {
                lock (syncRoot)
                {
                    //使用原子锁增加counter,当计数器为10时代表所有并行任务已经启动
                    if (Interlocked.Increment(ref counter) == 10)
                    {
                        lock (parallelStartSyncRoot)
                        {
                            //通知并行任务已经全部启动,并释放parallelStartSyncRoot锁
                            Monitor.Pulse(parallelStartSyncRoot);
                        }
                    }

                    Console.WriteLine(string.Format("[{0}] Waiting For syncRoot notify.", i));

                    //等待syncRoot通知,并释放syncRoot锁
                    Monitor.Wait(syncRoot);
                    Console.WriteLine(string.Format("[{0}] syncRoot notify received.", i));
                }
            });

            Console.Read();
        }

该程序是个多线程的应用,程序的逻辑将会严格按照以下顺序执行

(1)[主线程] 启动Task线程,等待taskStartSyncRoot,暂时释放syncRoot锁

(2)[TASK线程] 锁住parallelStartSyncRoot 和 taskStartSyncRoot(这里会等待主线程进入Wait状态),通知taskStartSyncRoot已经启动

(3)[TASK线程] 等待parallelStartSyncRoot,暂时释放parallelStartSyncRoot锁

(4)[Parallel子线程] Parallel并行任务启动,并且等待syncRoot,暂时释放syncRoot锁

(5)[最后一个Parallel子线程] 通知parallelStartSyncRoot已经全部启动

(6)[TASK线程] 等待锁syncRoot

(7)[最后一个Parallel子线程] 等待syncRoot,这时会暂时释放syncRoot锁

(8)[TASK线程] 获得syncRoot锁,并且通知(Monitor.PulseAll)所有syncRoot等待者(所有并行任务)。

程序的执行结果:

总结:要理解该多线程程序,必须要理解这三个锁对象的操作,以及通知机制的应用,从而可以让Task和多个并行任务有序的进行执行,大家在这里需要掌握几个知识点:

(1)在Monitor.Wait对象时必须获得目标对象的锁,以确保进入临界状态

(2)Monitor.Wait方法调用时,会将目标对象锁释放,在Wait完成时会重新获得该锁

 

抱歉!评论已关闭.