Monitor和lock

本文探讨了Monitor.TryEnter与lock在多线程环境下的不同应用。Monitor.TryEnter提供了更灵活的锁机制,适用于线程可以放弃锁或有其他选择的情况,而lock则确保线程在获取锁前会一直等待。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

其实两者的功能都是确保当一个线程位于代码的临界区时,另一个线程不进入临界区。Monitor.TryEnter方法就是获取对象的排它锁是否成功(方法具体版本可以参考MSDN);lock语句就是Monitor.Enter和Monitor.Exit的封装。MSDN里描述Monitor.TryEnter无论有没有获取对象锁都会返回结果,而Lock会在外面等直到占用的线程退出下一个线程才能进去。首先用代码测试两者的效果:
    class Class1
     {
         ///<summary>
         /// 应用程序的主入口点。
         ///</summary>
         [STAThread]
         static void Main(string[] args)
         {
              //
              // TODO: 在此处添加代码以启动应用程序
              //
              for(int k =0;k<100;k++)
              {
                   System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(SetAdd));
                   thread.Start();
              }
              System.Threading.Thread.Sleep(40000);
              Console.Write(i);
              Console.Read();
         }
         static int i = 0;
         private static object _LockObj = new object();
         public static void Add()
         {
              if(System.Threading.Monitor.TryEnter(_LockObj))//lock(typeof(this))
              {
                   try
                   {
                       i++;
                       System.Threading.Thread.Sleep(1);
                   }
                   finally
                   {
                       System.Threading.Monitor.Exit(_LockObj);
                   }
 
                  
              }
         }
         private static void SetAdd()
         {
              for(int i =0;i<100;i++)
              {
                   Add();
              }
         }
     }
上面的代码在运行的结果Monitor.TryEnter语句下i并不能完成所有数的累加,如果用lock结果i完成所有数的累加。正如MSDN所说Monitor.TryEnter在没有锁对象的情况下进行等待,而lock就处于等待直到完成。在执行过程方法或对象是所有线程唯的,那只好用lock;如果线程对锁操作可以弃或者有别的选择的情况可以采用Monitor.TryEnte;例如自己建立连接对象缓冲池就是线程在锁的情况下有多个选择。
 
从缓冲池获取连接对象首先是判连接对象是否可用,如果可用的情况下就进入对象锁操作方法获取对象的排它锁,在锁定对象后要处理一些东西如把连接对象的状态改变,标识一下个线程不能获取这个对象命用权并返回可用的连接对象等操作。如果我们用lock语来上锁,那么当一个线程在锁定对象后在作别的操作同时其他线程是在等待的;例如有两个线程X和Y,X先进入Connection1锁方法的临界区代码,那么Y就必须在外面等待其实这种等待是没意义的;因为Connection1已经被使用了在没有释的情况下Y线程进入锁操作的方法也是不允许获取这个对象使用权的。
Public bool Lock()
{
    lock(this)
    {
        if(!IsLock)
        {
            ………..
            ………..
IsLock =true;
            Return true;
        }
        return false;
}
}
其实Y线程根本不应该等待,当Y不能进入Connection1锁操作方法时就应该马上放弃等待,对下一个对象进行请求。
Public bool Lock()
{
    Monitor.TryEnter(this)
    {
        try
{
if(!IsLock)
        {
            ………..
            ………..
IsLock =true;
            Return true;
        }
        return false;
}  
finally
{
    Monitor.Exit(this);
}
}
}
Monitor.TryEnte提供灵活锁的方案,也可以很好地解决死锁等问题。
 
Monitor lock 关键字都是用于线程同步的机制,用于防止多个线程访问共享资源时出现竞态条件等问题。 1. lock 关键字 lock 关键字在 C# 中是一种独占锁机制,用于确保在同一时刻只有一个线程可以访问被锁定的代码块。使用 lock 关键字的代码示例: ``` object lockObject = new object(); lock(lockObject) { // 要被锁定的代码块 } ``` 在上面的代码中,lockObject 是一个用于锁定的对象,只有获取到 lockObject 的锁的线程才能进入被锁定的代码块。如果其他线程尝试获取 lockObject 的锁,则会被阻塞,直到锁被释放。 2. MonitorMonitor 类也是一种独占锁机制,与 lock 关键字的作用类似。使用 Monitor 类的代码示例: ``` object lockObject = new object(); Monitor.Enter(lockObject); try { // 要被锁定的代码块 } finally { Monitor.Exit(lockObject); } ``` 在上面的代码中,使用 Monitor.Enter() 方法获取锁,使用 Monitor.Exit() 方法释放锁。与 lock 关键字不同的是,使用 Monitor 类还可以调用 Monitor.Wait() 方法 Monitor.Pulse() 方法来实现线程的等待唤醒,例如: ``` object lockObject = new object(); // 线程1 Monitor.Enter(lockObject); try { // 检查条件是否满足 while(!condition) { Monitor.Wait(lockObject); } // 条件满足,执行代码 } finally { Monitor.Exit(lockObject); } // 线程2 Monitor.Enter(lockObject); try { // 更改条件 condition = true; // 唤醒线程1 Monitor.Pulse(lockObject); } finally { Monitor.Exit(lockObject); } ``` 在上面的代码中,线程1在等待条件满足时调用 Monitor.Wait() 方法来释放锁并等待被唤醒,线程2在更改条件后调用 Monitor.Pulse() 方法来唤醒线程1。需要注意的是,调用 Monitor.Wait() Monitor.Pulse() 方法时,需要获取锁并在 finally 块中释放锁,以确保锁的正确使用。 总之,lock 关键字 Monitor 类都是用于线程同步的机制,可以根据具体的情况选择使用。在使用时,需要注意线程安全锁的正确使用,避免出现死锁等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值