c#多线程编程笔记4

    技术2022-05-11  50

    a)        使用Monitor 

    Monitor类提供了锁定部分代码的简单机制,只要把受保护的代码包装在Monitor.EnterMonitor.Exit代码块中就行了。Monitor.Enter方法与Monitor.Exit方法都有一个参数。

    Monitor.Enter(object [obj]);Monitor.Exit(object [obj]).这个参数就是需要Monitor锁定的对象,它应该是一个引用类型,而不是值类型。

    Monitor具有以下功能:(摘自MSDN

           它根据需要与某个对象相关联。

           它是未绑定的,也就是说可以直接从任何上下文调用它。

           不能创建Monitor类的实例。

    例子6:

    using System;

    using System.Collections.Generic;

    using System.Text;

    using System.Threading;

     

    namespace ConsoleApplication1

    {

        public class MonitorClass6

        {

            protected static int m_iCounter = 0;

            public void Increment()

            {

                m_iCounter++;

            }

            public int Counter

            {

                get

                {

                    return m_iCounter;

                }

            }

        }

        public class test

        {

            public MonitorClass6 mc6 = new MonitorClass6();

     

            public void increseMC6()

            {

                Monitor.Enter(mc6);//进入临界区

                try

                {

                    mc6.Increment();

                    Console.WriteLine("线程{0}的值为{1}",Thread.CurrentThread.Name,mc6.Counter);

                }

                finally

                {

                    Monitor.Exit(mc6);//退出临界区

                }

            }

        }

     

        public class MainEntryPoint

        {

            public static test myTest = new test();

            public static void Main ()

            {

                ThreadStart ts1 = new ThreadStart(execute);

                Thread t1 = new Thread(ts1);

                t1.Name = "Thread1";

     

                ThreadStart ts2 = new ThreadStart(execute1);

                Thread t2 = new Thread(ts2);

                t2.Name = "Thread2";

     

                t1.Start();

                t2.Start();

                Console.Read();

            }

     

            public static void execute()

            {

                for (int i = 0; i <5; i++)

                {

                    myTest.increseMC6();

                }

            }

            public static void execute1()

            {

                for (int i = 0; i < 5; i++)

                {

                    myTest.increseMC6();

                }

            }

        }

    }

    执行结果如下:

    可以看到它没有经过顺序上的紊乱就达到10;如果我们把两个有带有Monitor注释掉,结果会变成下图所示(您机子上的结果也许顺序不一样)

    可以看出,由于我们没有对临界资源加以控制,而形成了我们不需要的“脏”数据!

    也许细心的你会发现这个Monitor类的形式与使用LOCK关键字基本一致,但我认为它比lock关键字强大一些,因为Monitor类还具有 TryEnter(试图获取指定对象的排他锁)、Wait(释放对象上的锁并阻止当前线程)、Pulse(能知等待队列中的线程锁定对象状态的更改)以及PulseAll(通知所有的等待线程的对象状态已改变)等方法。

    l         TtyEnter

     其方法的重载:

    Monitor.TryEnter(Object):试图获得指定对象的排他锁

    Monitor.TryEnter(Object,Int32):在指定的毫秒数内尝试获取指定对象上的排他锁

    Monitor.TryEnter(Object,TimeSpan):在指定的时间量内尝试获取指定对象上的排他锁

    将例子6increseMC6方法改为如下:

            public void increseMC6()

            {

                if (Monitor.TryEnter(mc6))//进入临界区

                {

                    try

                    {

                        mc6.Increment();

                        Console.WriteLine("线程{0}的值为{1}", Thread.CurrentThread.Name, mc6.Counter);

                    }

                    finally

                    {

                        Monitor.Exit(mc6);//退出临界区

                    }

                }

                else

                {

                    Console.WriteLine("线程{0}没有竞得资源",Thread.CurrentThread.Name);

                }

            }

    }

    l         Wait

    其方法的重载:

    Monitor.Wait(Object):释放对象上的锁并阻止当前线程,直到它重新获取该锁

    Monitor.Wait(Object,Int32):释放对象上的锁并阻止当前线程,直到它重新获取该锁。如果指定的超时间隔已过,则线程进入就绪队列。

    Monitor.Wait(Object,TimeSpan):同上。

    Monitor.Wait(Object,Int32,Boolean):前两个与第二个一样。其中的Boolean表示是否在等待之前退出上下文的同步域然后重新获取该同步域。

    Monitor.Wait(Object,TimeSpan,Boolean):同上。

    例程7

    using System;

    using System.Collections.Generic;

    using System.Text;

    using System.Threading;

     

    namespace ConsoleApplication1

    {

        public class Monitor7

        {

            protected int m_iCounter = 0;

     

            public void Increment()

            {

                m_iCounter++;

            }

     

            public int Counter

            {

                get

                {

                    return m_iCounter;

                }

            }

        }

     

        public class MonitorPulseClass

        {

            protected Monitor 7 m _protectedResource = new Monitor7();

            protected void ThreadOneMethod()

            {

                for (int i = 0; i < 5; i++)

                {

                    lock (m_protectedResource)

                    {

                        Console.WriteLine("进入第一个线程,I的值为:{0}",i);

                        Monitor.Wait(m_protectedResource);

                        m_protectedResource.Increment();

                        int iValue = m_protectedResource.Counter;

                        Console.WriteLine("{Thread One} - Current value of counter:" + iValue.ToString());

                    }

                }

            }

            protected void ThreadTwoMethod()

            {

                for (int i = 0; i < 5; i++)

                {

                    lock (m_protectedResource)

                    {

                        Console.WriteLine("进入第二个线程,I的值为:{0}",i);

                        int iValue = m_protectedResource.Counter;

                        Console.WriteLine("{Thread Two} - Current value of counter" + iValue.ToString());

                        Monitor.PulseAll(m_protectedResource);

                    }

                }

            }

     

            static void Main ()

            {

                MonitorPulseClass exampleClass = new MonitorPulseClass();

     

                Thread threadOne = new Thread(new ThreadStart(exampleClass.ThreadOneMethod));

                Thread threadTwo = new Thread(new ThreadStart(exampleClass.ThreadTwoMethod));

     

                threadOne.Start();

                threadTwo.Start();

                System.Console.Read();

            }

        }

    }

    执行结果如下:由此可以得到流程如下:首先进入thread1然后被Monitor.Wait中断,从而进入thread2,thread2中结束之后,通过Monitor.PulseAll通知thread1并执行,但又被Monitor.wait中断退出。

     

    最新回复(0)