繁体   English   中英

我的通过密钥(字符串)锁定关键部分的算法的缺陷在哪里?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM