C#多线程Monitor类锁定资源Monitor.TryEnter()的用法。通过一个例子告诉你什么是死锁。和解决方案

Monitor.TryEnter(lock1, TimeSpan.FromSeconds(5))

该方法是检查锁对象在指定时间内是否释放资源,如果释放则返回true否则false

下面是死锁的例子:(大家复制到自己VS中跑一下,我给的是完整控制台代码,打断点调试一下,结合着我的注释,写的很详细。应该会理解的。)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using static System.Console;
using static System.Threading.Thread;

namespace _9.Monitor类锁定资源
{
    class Program
    {
        static void Main(string[] args)
        {
            object lock1 = new object();
            object lock2 = new object();
            new Thread(()=>LockTooMuch(lock1,lock2)).Start();
            lock (lock2)
            {
                Thread.Sleep(1000);
                //监视器.TryEnter允许不被卡住,在指定的超时时间过后返回false
                WriteLine("Monitor.TryEnter allows not to get stuck,returning false after a specified timeout is elapsed");
                //判断当前锁的对象是否释放,超时就代表还未释放。
                if (Monitor.TryEnter(lock1, TimeSpan.FromSeconds(5)))
                {
                    //成功获取受保护的资源
                    WriteLine("cquired a protected resoured resource succesfully");
                }
                else
                {
                    //获取资源超时
                    WriteLine("Timeout acquiring a resource!");
                }
            }
            new Thread(()=> { LockTooMuch(lock1, lock2); }).Start();

            WriteLine("---------------------------");
            lock (lock2)//-----------------此时主线程已经锁死lock2
            {   
                //这是一个死锁
                WriteLine("This will be a deadlock");
                Sleep(1000);
                lock (lock1)   //=============主线程等待子线程释放lock1
                {
                    //已成功获取受保护的资源
                    WriteLine("Acquired a protected resource succesfully");
                }
            }
        }
        //上下俩段注释对比发现   主线程的lock2锁死导致子线程无法释放lock1  因为子线程在等待着主线程释放lock2  此时就造成了死锁。

        static void LockTooMuch(object lock1 ,object lock2)
        {
            lock (lock1)//=============子线程已经锁死lock1
            {
                Sleep(1000);
                lock (lock2);  //----------------子线程等待着主线程的lock2释放   子线程处于等待状态
            }
        }

    }
}

大概解释一下:(一定要自己跑一遍,打断点调试。)
先看 看 LockTooMuch 方法。 在 该 方法 中 我们 先 锁定 了 第一个 对象, 等待 一秒 后 锁定 了 第二个 对象。 然后 在另 一个 线程 中 启动 该 方法。 最后 尝试 在 主 线程 中 先后 锁定 第二个 和 第一个 对象。 如果 像 该 示例 的 第二 部分 一样 使用 lock 关键字, 将会 造成 死锁。 第一个 线程 保持 对 lock1 对象 的 锁定, 等待 直到 lock2 对象 被 释放。 主线 程 保持 对 lock2 对象 的 锁定 并 等待 直到 lock1 对象 被 释放, 但 lock1 对象 永远 不会 被 释放。 实际上 lock 关键字 是 Monitor 类 用 例 的 一个 语法 糖。 如果 我们 分解 使用 了 lock 关键字 的 代码, 将会 看到 它 如下 面 代码 片段 所示:

 bool acquiredLock = false;
            try
            {
                访问受锁保护的资源的代码
                Monitor.Enter(lockObject, ref acquiredLock);
                //Code that accesses resources that are protected by the lock
            }
            finally
            {
                if (acquiredLock)
                {
                    Monitor.Exit(lockObject);
                }
            }

因此, 我们 可以 直接 使用 Monitor 类。 其 拥有 TryEnter 方法, 该 方法 接受 一个 超时 参数。 如果 在 我们 能够 获取 被 lock 保护 的 资源 之前, 超时 参数 过期, 则 该 方法 会 返回 false。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值