[英]Where is the flaw in my algorithm to lock a critical section by a key (string)?
尝试:
public class KeyLock : IDisposable
{
private string key;
private static ISet<string> lockedKeys = new HashSet<string>();
private static object locker1 = new object();
private static object locker2 = new object();
public KeyLock(string key)
{
lock(locker2)
{
// wait for key to be freed up
while(lockedKeys.Contains(key));
this.lockedKeys.Add(this.key = key);
}
}
public void Dispose()
{
lock(locker)
{
lockedKeys.Remove(this.key);
}
}
}
像
using(new KeyLock(str))
{
// section that is critical based on str
}
我在同一时间两次触发该方法进行测试
private async Task DoStuffAsync(string str)
{
using(new KeyLock(str))
{
await Task.Delay(1000);
}
}
// ...
await Task.WhenAll(DoStuffAsync("foo"), DoStuffAsync("foo"))
但是,很奇怪的是,当我调试时,我看到它第二次直接通过lock
,实际上,无论如何,即使我在调试器窗口中看到该键在那里, lockedKeys.Contains(key)
计算结果lockedKeys.Contains(key)
false
。
该漏洞在哪里,我该如何解决?
看一下lock语句(C#参考)
它基本上分解为
object __lockObj = x;
bool __lockWasTaken = false;
try
{
System.Threading.Monitor.Enter(__lockObj, ref __lockWasTaken);
// Your code...
}
finally
{
if (__lockWasTaken) System.Threading.Monitor.Exit(__lockObj);
}
获取对指定 对象的排他锁。
相反,您需要做的就是获取并获得相同的参考。 您可能会使用线程安全字典ConcurrentDictionary
public static ConcurrentDictionary<string, object> LockMap = new ConcurrentDictionary<string, object> ();
...
lock (LockMap.GetOrAdd(str, x => new object ()))
{
// do locky stuff
}
注意 :这只是许多方法的一个示例,显然您需要根据需要对其进行调整
我注意到的主要问题如下:
※构造函数中的超级危险无限循环,也非常浪费。
※访问私有字段lockedKeys
,使用不同的对象进行锁定→不好
但是,我认为为什么您的代码似乎不起作用,是因为您设置的延迟很短。 当您从语句移到语句时,由于在调试过程中只有1秒的延迟,因此已经过去了1秒,并且将其丢弃。
using(new KeyLock(str)){
await Task.Delay(1000);
}
幸运的是,我之前遇到过类似的问题,我也有解决方案。 在这里寻找我的小解决方案。
用法:
//Resource to be shared
private AsyncLock _asyncLock = new AsyncLock();
....
....
private async Task DoStuffAsync()
{
using(await _asyncLock.LockAsync())
{
await Task.Delay(1000);
}
}
// ...
await Task.WhenAll(DoStuffAsync(), DoStuffAsync())
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.