实现分布式对象锁
在数据操作中经常需要锁一个对象来达到数据同步的目的;在一个应用程序中锁对象比较方便,因为c#提供了线程锁对象功能,但如果是不同服务器的数据操作需要锁对象就必须做一个对象锁服务了。
制定功能方法:
- Enter(string owner,string id, int milliseconds)
获取对象锁,直到获取拥用权再往下走
owner:锁的拥有者
id:锁的标识
milliseconds:锁对象的时间,超过这个时间即使程序没有释放标识,组件自动释放
Exit(string owner,string id)
owner:锁的拥有者 - TryEnter(string owner, string id, int milliseconds, int timeout)
获取对象锁,在指定时间内没有获取相关标识的锁就放弃往下执行
owner:锁的拥有者
id:锁的标识
milliseconds:锁对象的时间,超过这个时间即使程序没有释放标识,组件自动释放
timeout:超时时间 - TryEnter(string id, int milliseconds, int timeout, Smark.Core.AsyncDelegate<string> lockhandler)
获取对象锁,根据情况调用相关回委托
owner:锁的拥有者
id:锁的标识
milliseconds:锁对象的时间,超过这个时间即使程序没有释放标识,组件自动释放
timeout:超时时间
lockhandler:委托
代码
public class ObjectEnter:IDisposable
{
private string mOwnerID;
static ObjectEnter()
{
Core.Functions.Action(CheckExpires);
}
public ObjectEnter(string id)
{
mOwnerID = Guid.NewGuid().ToString("N");
mID = id;
Enter(mOwnerID, id, 60000);
}
public ObjectEnter(string id, int milliseconds)
{
mOwnerID = Guid.NewGuid().ToString("N");
mID = id;
Enter(mOwnerID, id, milliseconds);
}
private string mID = null;
private static Dictionary<string, LockItem> mObjectTable = new Dictionary<string, LockItem>(100);
public static void TryEnter(string id, Smark.Core.AsyncDelegate<string,bool> lockhandler)
{
TryEnter(id, 60000, 30000, lockhandler);
}
public static void TryEnter(string id, int milliseconds, int timeout, Smark.Core.AsyncDelegate<string,bool> lockhandler)
{
string owner = Guid.NewGuid().ToString("N");
if(lockhandler!=null)
lockhandler(owner,TryEnter(owner, id, milliseconds, timeout));
}
public static bool TryEnter(string owner, string id, int milliseconds, int timeout)
{
QueueState state = new QueueState();
state.EntrerMilliseconds = milliseconds;
state.TimeOut = timeout;
if (!GetLockItem(id).Enter(owner, milliseconds, state))
{
state.Handler.Reset();
state.Handler.WaitOne(state.TimeOut);
return GetLockItem(id).Enter(owner, milliseconds, null);
}
else
{
return true;
}
}
public static void Enter(string owner,string id, int milliseconds)
{
QueueState state = new QueueState();
state.EntrerMilliseconds = milliseconds;
if (!GetLockItem(id).Enter(owner, milliseconds, state))
{
state.Handler.Reset();
state.Handler.WaitOne();
}
}
public static void Exit(string owner,string id)
{
if (mObjectTable.ContainsKey(id))
mObjectTable[id].Exit(owner);
}
private static LockItem GetLockItem(string id)
{
lock (mObjectTable)
{
LockItem item = null;
if (!mObjectTable.ContainsKey(id))
{
item = new LockItem();
item.ID = id;
mObjectTable.Add(id, item);
}
else
{
item = mObjectTable[id];
}
return item;
}
}
private static void CheckExpires()
{
while (true)
{
lock (mObjectTable)
{
foreach (System.Collections.Generic.KeyValuePair<string, LockItem> item in mObjectTable)
{
item.Value.Expires();
}
}
System.Threading.Thread.Sleep(5000);
}
}
class LockItem
{
const string SYSTEM_ID = "SYSTEM_4EB49CA1-7470-44af-94DE-B2128B9B5BA9";
public LockItem()
{
}
public bool Enter(string owner, int milliseconds, QueueState handler)
{
lock (this)
{
if (Count>0 && owner != Owner)
{
if (handler != null)
EnterWait(handler);
return false;
}
Count++;
EntrerMilliseconds = milliseconds;
EnterTime = DateTime.Now;
return true;
}
}
private void EnterWait(QueueState handler)
{
lock (mWaitHandle)
{
mWaitHandle.Enqueue(handler);
}
}
private Queue<QueueState> mWaitHandle = new Queue<QueueState>();
public void Exit(string owner)
{
lock (this)
{
if (owner == SYSTEM_ID)
{
Owner = null;
Count = 0;
}
else
{
if (owner == Owner)
{
Count--;
}
}
if (Count == 0)
{
lock (mWaitHandle)
{
if (mWaitHandle.Count > 0)
{
QueueState state = mWaitHandle.Dequeue();
state.Handler.Set();
}
}
}
}
}
public int EntrerMilliseconds
{
get;
set;
}
public DateTime EnterTime
{
get;
set;
}
public string ID
{
get;
set;
}
public string Owner
{
get;
set;
}
public int Count
{
get;
set;
}
public void Expires()
{
lock (this)
{
TimeSpan ts = DateTime.Now - EnterTime;
if (ts.TotalMilliseconds > EntrerMilliseconds)
Exit(SYSTEM_ID);
}
}
}
#region IDisposable 成员
private bool mDisposed = false;
public void Dispose()
{
lock (this)
{
if (!mDisposed)
{
Exit(mID,mOwnerID);
mDisposed = true;
}
}
}
#endregion
}
class QueueState
{
public QueueState()
{
EntrerMilliseconds = 60000;
}
public bool Idle
{
get;
set;
}
public int EntrerMilliseconds
{
get;
set;
}
public int TimeOut
{
get;
set;
}
private System.Threading.EventWaitHandle mHandler = new EventWaitHandle(false, EventResetMode.ManualReset);
public System.Threading.EventWaitHandle Handler
{
get
{
return mHandler;
}
}
}
{
private string mOwnerID;
static ObjectEnter()
{
Core.Functions.Action(CheckExpires);
}
public ObjectEnter(string id)
{
mOwnerID = Guid.NewGuid().ToString("N");
mID = id;
Enter(mOwnerID, id, 60000);
}
public ObjectEnter(string id, int milliseconds)
{
mOwnerID = Guid.NewGuid().ToString("N");
mID = id;
Enter(mOwnerID, id, milliseconds);
}
private string mID = null;
private static Dictionary<string, LockItem> mObjectTable = new Dictionary<string, LockItem>(100);
public static void TryEnter(string id, Smark.Core.AsyncDelegate<string,bool> lockhandler)
{
TryEnter(id, 60000, 30000, lockhandler);
}
public static void TryEnter(string id, int milliseconds, int timeout, Smark.Core.AsyncDelegate<string,bool> lockhandler)
{
string owner = Guid.NewGuid().ToString("N");
if(lockhandler!=null)
lockhandler(owner,TryEnter(owner, id, milliseconds, timeout));
}
public static bool TryEnter(string owner, string id, int milliseconds, int timeout)
{
QueueState state = new QueueState();
state.EntrerMilliseconds = milliseconds;
state.TimeOut = timeout;
if (!GetLockItem(id).Enter(owner, milliseconds, state))
{
state.Handler.Reset();
state.Handler.WaitOne(state.TimeOut);
return GetLockItem(id).Enter(owner, milliseconds, null);
}
else
{
return true;
}
}
public static void Enter(string owner,string id, int milliseconds)
{
QueueState state = new QueueState();
state.EntrerMilliseconds = milliseconds;
if (!GetLockItem(id).Enter(owner, milliseconds, state))
{
state.Handler.Reset();
state.Handler.WaitOne();
}
}
public static void Exit(string owner,string id)
{
if (mObjectTable.ContainsKey(id))
mObjectTable[id].Exit(owner);
}
private static LockItem GetLockItem(string id)
{
lock (mObjectTable)
{
LockItem item = null;
if (!mObjectTable.ContainsKey(id))
{
item = new LockItem();
item.ID = id;
mObjectTable.Add(id, item);
}
else
{
item = mObjectTable[id];
}
return item;
}
}
private static void CheckExpires()
{
while (true)
{
lock (mObjectTable)
{
foreach (System.Collections.Generic.KeyValuePair<string, LockItem> item in mObjectTable)
{
item.Value.Expires();
}
}
System.Threading.Thread.Sleep(5000);
}
}
class LockItem
{
const string SYSTEM_ID = "SYSTEM_4EB49CA1-7470-44af-94DE-B2128B9B5BA9";
public LockItem()
{
}
public bool Enter(string owner, int milliseconds, QueueState handler)
{
lock (this)
{
if (Count>0 && owner != Owner)
{
if (handler != null)
EnterWait(handler);
return false;
}
Count++;
EntrerMilliseconds = milliseconds;
EnterTime = DateTime.Now;
return true;
}
}
private void EnterWait(QueueState handler)
{
lock (mWaitHandle)
{
mWaitHandle.Enqueue(handler);
}
}
private Queue<QueueState> mWaitHandle = new Queue<QueueState>();
public void Exit(string owner)
{
lock (this)
{
if (owner == SYSTEM_ID)
{
Owner = null;
Count = 0;
}
else
{
if (owner == Owner)
{
Count--;
}
}
if (Count == 0)
{
lock (mWaitHandle)
{
if (mWaitHandle.Count > 0)
{
QueueState state = mWaitHandle.Dequeue();
state.Handler.Set();
}
}
}
}
}
public int EntrerMilliseconds
{
get;
set;
}
public DateTime EnterTime
{
get;
set;
}
public string ID
{
get;
set;
}
public string Owner
{
get;
set;
}
public int Count
{
get;
set;
}
public void Expires()
{
lock (this)
{
TimeSpan ts = DateTime.Now - EnterTime;
if (ts.TotalMilliseconds > EntrerMilliseconds)
Exit(SYSTEM_ID);
}
}
}
#region IDisposable 成员
private bool mDisposed = false;
public void Dispose()
{
lock (this)
{
if (!mDisposed)
{
Exit(mID,mOwnerID);
mDisposed = true;
}
}
}
#endregion
}
class QueueState
{
public QueueState()
{
EntrerMilliseconds = 60000;
}
public bool Idle
{
get;
set;
}
public int EntrerMilliseconds
{
get;
set;
}
public int TimeOut
{
get;
set;
}
private System.Threading.EventWaitHandle mHandler = new EventWaitHandle(false, EventResetMode.ManualReset);
public System.Threading.EventWaitHandle Handler
{
get
{
return mHandler;
}
}
}
实现相关锁的WEB服务
代码
/// <summary>
/// 对象锁服务
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class ObjectEnterService : System.Web.Services.WebService
{
[WebMethod]
public string TryEnter(string id, int seconds, int timeout)
{
string owner = null;
Core.ObjectEnter.TryEnter(id, seconds * 1000, timeout * 1000, (o, Success) =>
{
if(Success)
owner = o;
});
return owner;
}
[WebMethod]
public void Exit(string owner, string id)
{
Core.ObjectEnter.Exit(owner, id);
}
}
/// 对象锁服务
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class ObjectEnterService : System.Web.Services.WebService
{
[WebMethod]
public string TryEnter(string id, int seconds, int timeout)
{
string owner = null;
Core.ObjectEnter.TryEnter(id, seconds * 1000, timeout * 1000, (o, Success) =>
{
if(Success)
owner = o;
});
return owner;
}
[WebMethod]
public void Exit(string owner, string id)
{
Core.ObjectEnter.Exit(owner, id);
}
}
服务比较简单如果能锁住对象就返回一个拥有者的ID,释放的时候需要转入这个拥有者的ID和锁标识.