以下假设对此代码有效吗?我在代码下面加了一些背景信息,但我认为它不相关。
假设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中的线程问题不太熟悉(我选择这种方法的原因之一)。根据可用的内容和我读到的内容,我认为上述内容应该有效,但我不确定并希望获得第二意见。
答案 0 :(得分:6)
您当前的解决方案看起来很不错。我要改变的两件事:
1:UnlockOnValue需要进入finally块。如果抛出异常,它将永远不会释放锁定。
2:LockOnValue效率有点低,因为它会进行两次字典查找。对于小字典而言,这不是什么大问题,但对于较大的字典,您需要切换到TryGetValue。
此外,你的假设3成立 - 至少目前如此。但是Dictionary合约不保证Keys属性总是返回相同的对象。而且由于不容易依赖于此,我建议不要这样做。每当我需要一个对象锁定时,我只是为了这个目的而创建一个对象。类似的东西:
private static Object _lock = new Object();
答案 1 :(得分:1)
lock
只有一个进程的范围。如果要跨越流程,则必须使用Mutex
(已命名)等原语。
lock
与Monitor.Enter
和Monitor.Exit
相同。如果您同时执行Monitor.Enter
和Monitor.Exit
,那也是多余的。
您不需要锁定读取,但是您必须锁定检查该值是否存在并添加它的“事务”。如果您没有锁定该系列指令,则在检查密钥和添加密钥并添加密钥时可能会出现其他问题 - 从而导致异常。您正在执行的锁定就足够了(您不需要对Enter和Exit进行额外调用 - 锁定会为您执行此操作)。