原生的lock作用域中,不能使用async,await关键词。
但高性能程序中lock逻辑大量存在,这里使用dispose接口支持的using逻辑,实现一个替代的lock逻辑:
public class NameTaskLock
{
static NameTaskLock m_only = new NameTaskLock();
public static NameTaskLock Current { get { return m_only; } }
public class NameLock : IDisposable
{
public string Key { get; private set; }
internal void ResetKey(string name)
{
this.Key = name;
}
public NameLock(string ask)
{
Key = ask;
}
public bool isReleased()
{
return string.IsNullOrEmpty(Key);
}
public void Dispose()
{
Key = null;
}
}
public readonly static int MaxWaitSecond = 10;//最大等待时间。超过该时间,会抛出异常。
public readonly static int MaxLockInMemery = 10000;//locked中最大的存储个数,超过该个数,会清理已销毁的NameLock项。
Dictionary<string, NameLock> locked = new Dictionary<string, NameLock>();
NameLock SetLock(string name)
{//为当前
lock (locked)
{
if (locked.ContainsKey(name))
{
var rt = locked[name];
if (rt.isReleased())
{
rt.ResetKey(name);
return rt;
}
else
return null;
}
else
{
NameLock rt = new NameLock(name);
locked[name] = rt;
return rt;
}
}
}
void ClearLock()
{
lock (locked)
{
var keys = locked.Keys.ToList();
foreach(var key in keys)
{
var theV = locked[key];
if (theV.isReleased())
locked.Remove(key);
}
}
}
public async Task<NameLock> GetLock(string name,int Second = -1)
{
if (locked.Count >= MaxLockInMemery)
ClearLock();
if (Second < 1)
Second = MaxWaitSecond;
DateTime enterTime = DateTime.Now;
while (true)
{
var rt = SetLock(name);
if (rt != null)
return rt;
else if ((DateTime.Now- enterTime).TotalSeconds > Second)
throw new Exception("NameTaskLock尝试超时,请检查使用名为:" + name + "的NameTaskLock资源使用逻辑。资源使用方未在"+ Second + "秒内结束任务。");
else
await Task.Delay(100);
}
}
}
使用方法:
using(var LKobj = await SVR.NameTaskLock.Current.GetLock("My Test Key Info"))
{
System.Threading.Thread.Sleep(1000);
Console.WriteLine(DateTime.Now.ToUniversalTime());
}
在using区间内相同名称的任务会互斥。 代价是每100毫秒检查一次其他任务是否完成。
问题:
1:如果使用 using(var LKobj = SVR.NameTaskLock.Current.GetLock("My Test Key Info")) 编译不会报错。 但如果发生互斥,将会有异常发生。
2:不能嵌套! 嵌套使用必然会发生超时异常。