c#多线程编程笔记4

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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值