9

以下假设是否适用于此代码?我在代码下放了一些背景信息,但我认为这无关紧要。

假设 1:由于这是一个单一的应用程序,我假设它将由一个进程处理。因此,静态变量在线程之间共享,并且静态声明我的锁对象集合是有效的。

假设 2:如果我知道该值已经在字典中,我不需要锁定读取。我可以使用 ConcurrentDictionary,但我相信这个会是安全的,因为我没有枚举(或删除),并且当我调用UnlockOnValue().

假设 3:我可以锁定 Keys 集合,因为该引用不会改变,即使底层数据结构会改变。

private static Dictionary<String,Object> LockList = 
    new Dictionary<string,object>();

private void LockOnValue(String queryStringValue)
{
    lock(LockList.Keys)
    {
        if(!LockList.Keys.Contains(queryStringValue))
        {
            LockList.Add(screenName,new Object());
        }
        System.Threading.Monitor.Enter(LockList[queryStringValue]);
    }
}

private void UnlockOnValue(String queryStringValue)
{
    System.Threading.Monitor.Exit(LockList[queryStringValue]);
}

然后我会使用这样的代码:

LockOnValue(Request.QueryString["foo"])
//Check cache expiry
//if expired
    //Load new values and cache them.
//else
    //Load cached values
UnlockOnValue(Request.QueryString["foo"])

背景: 我正在 ASP.NET 中创建一个应用程序,该应用程序根据查询字符串中的单个用户定义变量下载数据。值的数量将非常有限。我需要在指定的时间段内缓存每个值的结果。

方法:我决定使用本地文件来缓存数据,这不是最好的选择,但我想尝试一下,因为这不重要,性能也不是大问题。我每个选项使用 2 个文件,一个带有缓存到期日期,一个带有数据。

问题:我不确定执行锁定的最佳方法是什么,而且我对 .NET 中的线程问题并不太熟悉(我选择这种方法的原因之一)。根据可用的内容以及我阅读的内容,我认为上述内容应该可行,但我不确定并想要第二意见。

4

2 回答 2

7

您当前的解决方案看起来不错。我要改变的两件事:

1:UnlockOnValue 需要进入 finally 块。如果抛出异常,它永远不会释放它的锁。

2:LockOnValue 有点低效,因为它会进行两次字典查找。这对于小型字典来说没什么大不了的,但对于较大的字典,您将需要切换到 TryGetValue。

此外,您的假设 3 成立 - 至少目前如此。但是 Dictionary 契约不保证 Keys 属性总是返回相同的对象。而且由于很容易不依赖它,我建议不要这样做。每当我需要锁定一个对象时,我只是为此目的创建一个对象。就像是:

private static Object _lock = new Object();
于 2012-07-24T17:04:32.700 回答
1

lock仅具有单个进程的范围。如果你想跨越进程,你将不得不使用像Mutex(named) 这样的原语。

lockMonitor.Enter与和相同Monitor.Exit。如果你也这样做Monitor.Enterand Monitor.Exit,那是多余的。

您不需要锁定读取,但您必须锁定检查值是否不存在并添加它的“事务”。如果您不锁定该系列指令,则在您检查密钥和添加并添加密钥之间可能会出现其他情况,从而导致异常。您正在做的锁足以做到这一点(您不需要额外调用 Enter 和 Exit —— lock 会为您做到这一点)。

于 2012-07-23T20:18:44.003 回答