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
315 lines
7.7 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|