mirror of
				https://gitee.com/ThingsGateway/ThingsGateway.git
				synced 2025-10-31 23:53:58 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			86 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			86 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| namespace ThingsGateway.NewLife.Caching;
 | |
| 
 | |
| /// <summary>分布式锁</summary>
 | |
| public class CacheLock : DisposeBase
 | |
| {
 | |
|     private ICache Client { get; set; }
 | |
| 
 | |
|     /// <summary>
 | |
|     /// 是否持有锁
 | |
|     /// </summary>
 | |
|     private Boolean _hasLock = false;
 | |
| 
 | |
|     /// <summary>键</summary>
 | |
|     public String Key { get; set; }
 | |
| 
 | |
|     /// <summary>实例化</summary>
 | |
|     /// <param name="client"></param>
 | |
|     /// <param name="key"></param>
 | |
|     public CacheLock(ICache client, String key)
 | |
|     {
 | |
|         if (client == null) throw new ArgumentNullException(nameof(client));
 | |
|         if (key.IsNullOrEmpty()) throw new ArgumentNullException(nameof(key));
 | |
| 
 | |
|         Client = client;
 | |
|         Key = key;
 | |
|     }
 | |
| 
 | |
|     /// <summary>申请锁</summary>
 | |
|     /// <param name="msTimeout">锁等待时间,申请加锁时如果遇到冲突则等待的最大时间,单位毫秒</param>
 | |
|     /// <param name="msExpire">锁过期时间,超过该时间如果没有主动释放则自动释放锁,必须整数秒,单位毫秒</param>
 | |
|     /// <returns></returns>
 | |
|     public Boolean Acquire(Int32 msTimeout, Int32 msExpire)
 | |
|     {
 | |
|         var ch = Client;
 | |
|         var now = Runtime.TickCount64;
 | |
| 
 | |
|         // 循环等待
 | |
|         var end = now + msTimeout;
 | |
|         while (now < end)
 | |
|         {
 | |
|             // 申请加锁。没有冲突时可以直接返回
 | |
|             var rs = ch.Add(Key, now + msExpire, msExpire / 1000);
 | |
|             if (rs) return _hasLock = true;
 | |
| 
 | |
|             // 死锁超期检测
 | |
|             var dt = ch.Get<Int64>(Key);
 | |
|             if (dt <= now)
 | |
|             {
 | |
|                 // 开抢死锁。所有竞争者都会修改该锁的时间戳,但是只有一个能拿到旧的超时的值
 | |
|                 var old = ch.Replace(Key, now + msExpire);
 | |
|                 // 如果拿到超时值,说明抢到了锁。其它线程会抢到一个为超时的值
 | |
|                 if (old <= dt)
 | |
|                 {
 | |
|                     ch.SetExpire(Key, TimeSpan.FromMilliseconds(msExpire));
 | |
|                     return _hasLock = true;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             // 没抢到,继续
 | |
|             Thread.Sleep(200);
 | |
| 
 | |
|             now = Runtime.TickCount64;
 | |
|         }
 | |
| 
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /// <summary>销毁</summary>
 | |
|     /// <param name="disposing"></param>
 | |
|     protected override void Dispose(Boolean disposing)
 | |
|     {
 | |
|         base.Dispose(disposing);
 | |
| 
 | |
|         // 如果客户端已释放,则不删除
 | |
|         if (Client is DisposeBase db && db.Disposed)
 | |
|         {
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             if (_hasLock)
 | |
|             {
 | |
|                 Client.Remove(Key);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| } | 
