C# Monitor:锁定资源

本文深入探讨了C#中的Monitor类和Lock关键字,详细解释了如何使用它们进行多线程同步,包括Monitor的Enter、Exit、TryEnter等方法,以及Lock的语法糖特性。通过代码示例展示了两者的实际应用。
部署运行你感兴趣的模型镜像

C#中, 通过System.Threading.Monitor类可以实现多线程中对某些代码块的同步访问,以确保数据的安全性。

object obj=new object();

Monitor在锁对象obj上会维持两个线程队列R和W以及一个引用T :

(1) T是对当前获得了obj锁的线程的引用(设此线程为CurrThread); 

(2) R为就绪队列, 其上的线程已经准备好获取obj锁。当obj锁被CurrThread释放后(CurrThread可通过Monitor.Exit(obj)或 Monitor.Wait(obj)来释放其所获的obj锁)这些线程就会去竞争obj锁,获得obj锁的线程将被T引用; 线程调用Monitor.Enter(obj)或Monitor.TryEnter(obj)将会使该线程直接进入R队列。

(3) W为等待队列,其上的线程是因为调用了Monitor.Wait(obj)而进入W队列的;W上的线程不会被OS直接调度执行,也就是说它们没有准备好获取obj锁,就是说在等待队列上的线程不能去获得obj锁。当前获得obj锁的线程CurrThread调用Monitor.Pulse(obj)或Monitor.PulseAll(obj)后会使W队列中的第一个等待线程或所有等待线程被移至R队列,这时被移至R队列的这些线程就有机会被OS直接调度执行,也就是有可以去竞争obj锁。

lock 关键字

lock 关键字可以作为Monitor类的一个替代。下面两个代码块是等效的:

Monitor.Enter(this);
//...
Monitor.Exit(this);


lock (this)
{
    //...
}

在这里,object 值与 lock 中的 object 值是一样的。

简而言之,lock 的写法是 Monitor 类的一种简写。

【实例】将上一节《C# lock》实例中的 lock 关键字替换成 Monitor 类。

根据题目要求,代码如下。

class Program
{
    public void PrintEven()
    {
        Monitor.Enter(this);
        try
        {
            for(int i = 0; i <= 10; i = i + 2)
            {
                Console.WriteLine(Thread.CurrentThread.Name + "--" + i);
            }
        }
        finally
        {
            Monitor.Exit(this);
        }
    }
    public void PrintOdd()
    {
        Monitor.Enter(this);
        try
        {
            for(int i = 1; i <= 10; i = i + 2)
            {
                Console.WriteLine(Thread.CurrentThread.Name + "--" + i);
            }
        }
        finally
        {
            Monitor.Exit(this);
        }
    }
    static void Main(string[] args)
    {
        Program program = new Program();
        ThreadStart ts1 = new ThreadStart(program.PrintOdd);
        Thread t1 = new Thread(ts1);
        t1.Name = "打印奇数的线程";
        t1.Start();
        ThreadStart ts2 = new ThreadStart(program.PrintEven);
        Thread t2 = new Thread(ts2);
        t2.Name = "打印偶数的线程";
        t2.Start();
    }
}

运行该程序,效果如下图所示。

9b4f295f4723f24539603f3faac58de3.png

Monitor 类的TryEnter() 方法在尝试获取一个对象上的显式锁方面和 Enter() 方法类似。然而,它不像Enter()方法那样会阻塞执行。如果线程成功进入关键区域那么TryEnter()方法会返回true.

Monitor 类的用法虽然比 lock 关键字复杂,但其能添加等待获得锁定的超时值,这样就不会无限期等待获得对象锁。

使用 TryEnter() 方法可以给它传送一个超时值,决定等待获得对象锁的最长时间。

使用 TryEnter() 方法设置获得对象锁的时间的代码如下。

Monitor.TryEnter(object, 毫秒数 );

该方法能在指定的毫秒数内结束线程,这样能避免线程之间的死锁现象。

此外,还能使用 Monitor 类中的 Wait() 方法让线程等待一定的时间,使用 Pulse() 方法通知处于等待状态的线程。

 C#中Monitor和Lock简介及区别

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

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

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

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

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

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

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

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

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

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

Lock关键字

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

  2.Lock关键字封装的Monitor对象结构如下:

try
            {
                Monitor.Enter(obj);
                dosomething();
            }
            catch(Exception ex)
            {
                
            }
            finally
            {
                Monitor.Exit(obj);
            }

 3.锁定的对象应该声明为private static object obj = new object();尽量别用公共变量和字符串、this、值类型。

Monitor和Lock的区别

  1.Lock是Monitor的语法糖。

  2.Lock只能针对引用类型加锁。

  3.Monitor能够对值类型进行加锁,实质上是Monitor.Enter(object)时对值类型装箱。

  4.Monitor还有其他的一些功能。

本文代码示例:

class Program
    {
        private static object obj = new object();
        public void LockSomething()
        {
            lock (obj)
            {
                dosomething();
            }
        }
        public void MonitorSomeThing()
        {
            try
            {
                Monitor.Enter(obj);
                dosomething();
            }
            catch(Exception ex)
            {
                
            }
            finally
            {
                Monitor.Exit(obj);
            }
        }


        public void dosomething()
        { 
            //做具体的事情
        }
    }

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zls365365

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值