Files
hjha-server/GameDAL/db/redis/DistributedLock.cs
xiaoou e9616125ce feat: initial commit - HJHA game server full source
6 major server modules (PdkFriendServer/GlobalSever/ServerCore/GameModule/GameNetModule) +
game logic (GameFix/GameDAL/ServerData) +
network layer (NetWorkMessage) +
data layer (ObjectModel) +
utilities (MrWu/Core/Config/CloudAPI/dll) +
adapters (zyxAdapter/base)

.NET 8.0 C# solution, 16 projects, 958 source files
2026-07-07 12:02:15 +08:00

315 lines
7.7 KiB
C#

/*
* 由SharpDevelop创建。
* 用户: Administrator
* 日期: 2018-10-24
* 时间: 9:56
*
* 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
*/
using System;
using System.Threading;
using MrWu.Debug;
using Server.DB.Redis;
using StackExchange.Redis;
using System.Threading.Tasks;
namespace Server.DB.Redis
{
/// <summary>
/// 分布式锁
/// </summary>
public class DistributedLock{
/// <summary>
/// 最大等待数量
/// </summary>
private readonly int maxWaitCnt;
/// <summary>
/// 锁的钥匙
/// </summary>
private readonly string[] lockKey;
/// <summary>
/// 下一个锁的位置
/// </summary>
private int nextid = -1;
/// <summary>
/// 读写锁
/// </summary>
private readonly ReaderWriterLockSlim rwls = new ReaderWriterLockSlim();
private volatile IDatabaseProxy m_db;
/// <summary>
/// 操作线程锁数据库
/// </summary>
private IDatabaseProxy db{
get{
if(m_db == null)
m_db = redisManager.db;
return m_db;
}
}
/// <summary>
/// 创建分布式锁
/// </summary>
/// <param name="waitMaxCnt">最大等待数量</param>
public DistributedLock(int waitMaxCnt){
maxWaitCnt = waitMaxCnt;
lockKey = new string[maxWaitCnt];
}
/// <summary>
/// 添加锁
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
private int AddKey(string key){
while(true){
rwls.EnterWriteLock();
try{
nextid++;
if(nextid >= maxWaitCnt)
nextid = 0;
if(lockKey[nextid] == null){
lockKey[nextid] = key;
return nextid;
}
}finally{
rwls.ExitWriteLock();
}
//SpinWait sw = new SpinWait();
//sw.SpinOnce();
Thread.Sleep(1);
}
}
/// <summary>
/// 删除锁
/// </summary>
/// <param name="idx"></param>
/// <returns></returns>
private void RemoveKey(int idx){
rwls.EnterWriteLock();
try{
lockKey[idx] = null;
}finally{
rwls.ExitWriteLock();
}
}
/// <summary>
/// 获取钥匙
/// </summary>
/// <param name="idx"></param>
/// <returns></returns>
private string GetKey(int idx){
rwls.EnterReadLock();
try{
return lockKey[idx];
}finally{
rwls.ExitReadLock();
}
}
/// <summary>
/// 为锁续航
/// </summary>
/// <param name="state"></param>
private void AddLockLife(object state){
Task.Factory.StartNew(()=>{
int idx = (int)state;
string key = GetKey(idx);
while(true){
Thread.Sleep(1000);
if(key == GetKey(idx) && key != null){
string strtimeOut = db.StringGet(key);
if(strtimeOut != null){
int timeOut;
if(int.TryParse(strtimeOut,out timeOut))
db.KeyExpire(key,new TimeSpan(0,0,timeOut));
else
Debug.Error("不可能的错误存储的值不是数字anckjnsakjbdnja,"+strtimeOut + "," + key);
}else{
break;
}
}else
break;
}
});
}
/// <summary>
/// 尝试运行
/// </summary>
/// <param name="key">key</param>
/// <param name="action">事件</param>
/// <param name="timeOut">key超时时间</param>
/// <param name="tryTimeOut">尝试超时时间</param>
/// <returns>是否运行</returns>
public bool TryLockRun(string key,Action action,int timeOut,int tryTimeOut = 0){
if(key == null){
Debug.Error("key不能为null");
return false;
}
key = key+".lock";
TimeSpan tm = new TimeSpan(0,0,timeOut);
DateTime lastTime = DateTime.Now;
//SpinWait sw = new SpinWait();
while(!db.StringSet(key,timeOut,tm,When.NotExists)){
if((DateTime.Now - lastTime).TotalMilliseconds >= tryTimeOut)
return false;
//sw.SpinOnce();
Thread.Sleep(1);
}
//Debug.Log("运算开始:" + key + "," + DateTime.Now.Millisecond.ToString());
Exception ex = null;
int idx = AddKey(key);
try{
AddLockLife(idx);
if(action != null)
action();
}catch(Exception e){
Debug.Error("处理出错:" + e.ToString());
ex = e;
}finally{
RemoveKey(idx);
//Debug.Log("运算结束:" + key + "," + DateTime.Now.Millisecond.ToString());
db.KeyDelete(key);
if(ex != null)
throw ex;
}
return true;
}
/// <summary>
/// 尝试运行
/// </summary>
/// <param name="key">key</param>
/// <param name="func">事件</param>
/// <param name="timeOut">timeOut</param>
/// <param name="result">返回结果</param>
/// <param name="tryTimeOut">尝试超时时间</param>
/// <returns>是否运行</returns>
public bool TryLockRun<T>(string key,Func<T> func,int timeOut,out T result,int tryTimeOut = 0){
result = default(T);
if(key == null){
Debug.Error("key不能为null");
return false;
}
key = key + ".lock";
TimeSpan tm = new TimeSpan(0,0,timeOut);
DateTime lastTime = DateTime.Now;
//SpinWait sw = new SpinWait();
while(!db.StringSet(key,timeOut,tm,When.NotExists)){
if((DateTime.Now - lastTime).TotalMilliseconds >= tryTimeOut)
return false;
//sw.SpinOnce();
Thread.Sleep(1);
}
Exception ex = null;
int idx = AddKey(key);
try{
AddLockLife(idx);
if(func != null)
result = func();
}catch(Exception e){
ex = e;
Debug.Error("处理出错:" + e.ToString());
}finally{
RemoveKey(idx);
Debug.Log("运算结束:" + key + "," + DateTime.Now.Millisecond.ToString());
db.KeyDelete(key);
if(ex != null)
throw ex;
}
return true;
}
/// <summary>
/// 加锁运行
/// </summary>
public void LockRun(string key,Action action,int timeOut = 3){
if(key == null){
Debug.Error("key不能为null");
return;
}
key = key+".lock";
TimeSpan tm = new TimeSpan(0,0,timeOut);
//SpinWait sw = new SpinWait();
while(!db.StringSet(key,timeOut,tm,When.NotExists)){
//sw.SpinOnce();
Thread.Sleep(1);
}
Exception ex = null;
int idx = AddKey(key);
try{
AddLockLife(idx);
if(action != null)
action();
}catch(Exception e){
ex = e;
}finally{
RemoveKey(idx);
db.KeyDelete(key);
if(ex != null)
throw ex;
}
}
/// <summary>
/// 加锁运行
/// </summary>
/// <param name="key"></param>
/// <param name="func"></param>
/// <param name="timeOut">超时时间</param>
/// <returns></returns>
public T LockRun<T>(string key,Func<T> func,int timeOut = 3){
T result = default(T);
if(key == null){
Debug.Error("key不能为null");
return result;
}
key = key + ".lock";
TimeSpan tm = new TimeSpan(0,0,timeOut);
//SpinWait sw = new SpinWait();
while(!db.StringSet(key,timeOut,tm,When.NotExists)){
//sw.SpinOnce();
Thread.Sleep(1);
}
Exception ex = null;
int idx = AddKey(key);
try{
AddLockLife(idx);
if(func != null)
result = func();
}catch(Exception e){
ex = new Exception("lockRun error :" , e);
}finally{
RemoveKey(idx);
db.KeyDelete(key);
if(ex != null)
throw ex;
}
return result;
}
}
}