• Lock 与Monitor 的用法与区别


    1.lock的底层本身是Monitor来实现的,所以Monitor可以实现lock的所有功能

    2.Monitor有TryEnter的功能,可以防止出现死锁的问题,lock没有。

    3.Monitor.Enter(object)方法是获取锁,Monitor.Exit(object)方法是释放锁,这就是Monitor最常用的两个方法,当然在使用过程中为了避免获取锁之后因为异常,致锁无法释放,所以需要在try{} catch(){}之后的finally{}结构体中释放锁(Monitor.Exit())。

    4.Monitor的常用属性和方法:

        Enter(Object) 在指定对象上获取排他锁。

        Exit(Object) 释放指定对象上的排他锁。

        IsEntered 确定当前线程是否保留指定对象锁。

        Pulse 通知等待队列中的线程锁定对象状态的更改。

        PulseAll 通知所有的等待线程对象状态的更改。

        TryEnter(Object) 试图获取指定对象的排他锁。

        TryEnter(Object, Boolean) 尝试获取指定对象上的排他锁,并自动设置一个值,指示是否得到了该锁。

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

    5.Lock关键字实际上是一个语法糖,它将Monitor对象进行封装,给object加上一个互斥锁,A进程进入此代码段时,会给object对象加上互斥锁,此时其他B进程进入此代码段时检查object对象是否有锁?如果有锁则继续等待A进程运行完该代码段并且解锁object对象之后,B进程才能够获取object对象为其加上锁,访问代码段。

    6.其实lock在IL代码中会被翻译成Monitor。也就是Monitor.Enter(obj)和Monitor.Exit(obj).

    lock(obj)
    {
    }
    等价为:
    try
    {    
          Monitor.Enter(obj) 
    }
    catch()
    {}
    finally
    {
          Monitor.Exit(obj) 
    }

    所以lock能做的,Monitor肯定能做,Monitor能做的,lock不一定能做。那么Monitor额外的功能呢?


    还有Monitor.Wait()和Monitor.Pulse()。在lock代码里面如果调用了Monitor.Wait(),会放弃对资源的所有权,让别的线程lock进来。然后别的线程代码里Pulse一下(让原线程进入到等待队列),然后在Wait一下释放资源,这样原线程的就可以继续执行了(代码还堵塞在wait那句话呢)。
    也就是说,必须两个或多个线程共同调用Wait和Pulse,把资源的所有权抛来抛去,才不会死锁。
    AutoEvent相似是处理同步关系的,但是AutoEvent是跨进程的,而Monitor是针对线程的。
    以下是MSDN的代码示例,调试起来很容易看出来两个函数的作用了,因为尽管是多线程程序,但是是同步操作,所以代码始终是单步执行的。
    using System;
    using System.Threading;
    using System.Collections;

    namespace MonitorCS1
    {
        class MonitorSample
        {
            const int MAX_LOOP_TIME = 100;
            Queue m_smplQueue;

            public MonitorSample()
            {
                m_smplQueue = new Queue();
            }
            public void FirstThread()
            {
                int counter = 0;
                lock (m_smplQueue)
                {
                    while (counter < MAX_LOOP_TIME)
                    {
                        //Wait, if the queue is busy.
                        Monitor.Wait(m_smplQueue);
                        //Push one element.
                        m_smplQueue.Enqueue(counter);
                        //Release the waiting thread.
                        Monitor.Pulse(m_smplQueue);

                        counter++;
                    }
                    int i = 0;
                }
            }
            public void SecondThread()
            {
                lock (m_smplQueue)
                {
                    //Release the waiting thread.
                    Monitor.Pulse(m_smplQueue);
                    //Wait in the loop, while the queue is busy.
                    //Exit on the time-out when the first thread stops.
                    while (Monitor.Wait(m_smplQueue, 50000))
                    {
                        //Pop the first element.
                        int counter = (int)m_smplQueue.Dequeue();
                        //Print the first element.
                        Console.WriteLine(counter.ToString());
                        //Release the waiting thread.
                        Monitor.Pulse(m_smplQueue);
                    }
                }
            }
            //Return the number of queue elements.
            public int GetQueueCount()
            {
                return m_smplQueue.Count;
            }

            static void Main(string[] args)
            {
                //Create the MonitorSample object.
                MonitorSample test = new MonitorSample();
                //Create the first thread.
                Thread tFirst = new Thread(new ThreadStart(test.FirstThread));
                //Create the second thread.
                Thread tSecond = new Thread(new ThreadStart(test.SecondThread));
                //Start threads.
                tFirst.Start();
                tSecond.Start();
                //wait to the end of the two threads
                tFirst.Join();
                tSecond.Join();
                //Print the number of queue elements.
                Console.WriteLine("Queue Count = " + test.GetQueueCount().ToString());
            }
        }
    }

    参考
     http://blog.sina.com.cn/s/blog_57a829dd01010zyp.html
  • 相关阅读:
    数字建模工具
    博客园文档保存为pdf适合手机kindle阅读
    单点登录sso规范
    office在线预览方案
    KVM 虚机怎么热添加disk
    linux-基础FTP 协议传输
    TCP 三次握手四次挥手
    autossh 实现反向代理实现通过外网访问内网环境
    keepalived的工作原理
    openstack-ovs命令记录
  • 原文地址:https://www.cnblogs.com/wangyonglai/p/8241724.html
Copyright © 2020-2023  润新知