C#多线程的用法5-线程间的协作Monitor

之前我们使用lock快捷方式,实现了多线程对同一资源的共享。在C#中lock实际上是Monitor操作的简化版本。

下面使用Monitor来完成之前的lock功能,你可以在此做一下对照:

private static void MultiThreadSynergicWithMonitor()
        {
            int[] array = new int[3];

            Thread producer = new Thread(() =>
            {
                int count = 0;
                Random random = new Random();
                while (true)
                {
                    if (10 == count)
                        break;

                    Monitor.Enter(array);
                    array[0] = random.Next(10);
                    array[1] = random.Next(10);
                    array[2] = random.Next(10);
                    count++;
                    Console.WriteLine(String.Format("{0} work count:{1}。{2}-{3}-{4}", Thread.CurrentThread.Name, count, array[0], array[1], array[2]));
                    Monitor.Exit(array);
                }
            })
            {
                Name = "producer"
            };
            Thread customer = new Thread(() =>
            {
                int count = 0;
                while (true)
                {
                    if (10 == count)
                        break;

                    Monitor.Enter(array);
                    count++;
                    Console.WriteLine(String.Format("{0} work count:{1}。{2}-{3}-{4}", Thread.CurrentThread.Name, count, array[0], array[1], array[2]));
                    array[0] = 0;
                    array[1] = 0;
                    array[2] = 0;
Monitor.Exit(array);
                }
                
            })
            {
                Name = "customer"
            };

            producer.Start();
            customer.Start();
        }

通过对比聪明的你可定发现,lock(xx){ }等效于 Monitor.Enter(x'x)与Monitor.Exit(xx)的组合,实际上lock就是Monitor的语法糖。

因此Monitor比lock在控制线程协作方面更为 强大,如下:

/// <summary>
        /// 多线程协作-Monitor方式
        /// 成功解决多线程对单一资源的共享
        /// 并解决多个线程间同步问题
        /// </summary>
        private static void MultiThreadSynergicWithMonitor()
        {
            int[] array = new int[3];

            Thread producer = new Thread(() =>
            {
                int count = 0;
                Random random = new Random();
                while (true)
                {
                    if (10 == count)
                        break;

                    Monitor.Enter(array);
                    array[0] = random.Next(10);
                    array[1] = random.Next(10);
                    array[2] = random.Next(10);
                    count++;
                    Console.WriteLine(String.Format("{0} work count:{1}。{2}-{3}-{4}", Thread.CurrentThread.Name, count, array[0], array[1], array[2]));
                    Monitor.Pulse(array);
                    Monitor.Wait(array);
                }
                Monitor.Exit(array);
            })
            {
                Name = "producer"
            };
            Thread customer = new Thread(() =>
            {
                int count = 0;
                while (true)
                {
                    if (10 == count)
                        break;

                    Monitor.Enter(array);
                    count++;
                    Console.WriteLine(String.Format("{0} work count:{1}。{2}-{3}-{4}", Thread.CurrentThread.Name, count, array[0], array[1], array[2]));
                    array[0] = 0;
                    array[1] = 0;
                    array[2] = 0;
                    Monitor.Pulse(array);
                    Monitor.Wait(array);
                }
                Monitor.Exit(array);
            })
            {
                Name = "customer"
            };

            producer.Start();
            customer.Start();
        }

  上面的代码与之前的lock代码功能类似但却不相同,它实现了producer线程与customer线程的交替运行(与lock方式相比控制更加精细),再次建议你执行一下实际代码,你会很容易发现两者却别。

说明:

1、Monitor.Pulse(xx)实现通知等待xx资源的某一个线程由等待状态(等待队列)变更为就绪状态(就绪队列),从而做好准备在调用Monitor.Pulse(x'x)功能的线程释放资源时马上锁定释放的资源。

2、Monitor.Wait(xx)实现调用该方法的线程暂时释放锁定的资源,并让该线程进入等待线程队列。所以线程在调用该方法后会临时中断后续代码的执行,在该线程再次获得资源时,

将回到中断继续执行。

3、Monitor.PulseAll(xx)是Monitor.Pulse(xx)扩大版,如果你理解了Monitor.Pulse(xx)并且知道线程状态的变更(线程所属队列的变化),那么理解Monitor.PulseAll就简单多了

Monitor.PulseAll实现将所有等待资源的线程由等待状态变为就绪状态,接下来如果资源被释放,所有就绪线程将均有机会获得资源并执行。

posted @ 2017-08-20 18:27  DW039  阅读(655)  评论(0编辑  收藏  举报