在ASP.NET中运行时创建动态锁

时间:2012-07-23 17:40:34

标签: c# asp.net thread-safety

以下假设对此代码有效吗?我在代码下面加了一些背景信息,但我认为它不相关。

假设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中的线程问题不太熟悉(我选择这种方法的原因之一)。根据可用的内容和我读到的内容,我认为上述内容应该有效,但我不确定并希望获得第二意见。

2 个答案:

答案 0 :(得分:6)

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

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

2:LockOnValue效率有点低,因为它会进行两次字典查找。对于小字典而言,这不是什么大问题,但对于较大的字典,您需要切换到TryGetValue。

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

private static Object _lock = new Object();

答案 1 :(得分:1)

lock只有一个进程的范围。如果要跨越流程,则必须使用Mutex(已命名)等原语。

lockMonitor.EnterMonitor.Exit相同。如果您同时执行Monitor.EnterMonitor.Exit,那也是多余的。

您不需要锁定读取,但是您必须锁定检查该值是否存在并添加它的“事务”。如果您没有锁定该系列指令,则在检查密钥和添加密钥并添加密钥时可能会出现其他问题 - 从而导致异常。您正在执行的锁定就足够了(您不需要对Enter和Exit进行额外调用 - 锁定会为您执行此操作)。