我正在使用Azure共享缓存在服务器端的Web服务器上处理缓存层,以减少对数据库的请求量,从而使运行更快(希望如此)。我所困扰的是如何使整个精心打造的线程安全。我似乎找不到一种可靠且可用的方法来锁定DataCache中的密钥。我缺少的是一种在存储任何内容之前保护锁定密钥的方法,这样我就可以添加一个值而不会有另一个线程试图同时执行相同操作的风险。 / p>
到目前为止,我一直专注于悲观锁定,因为线程安全对我来说最有意义,我想确保我正在处理的东西被锁定。
我已经明白,如果我要使用悲观锁定,我只负责使用与之相关的方法。混合的东西会搞乱整个锁定机制(来源:http://go4answers.webhost4life.com/Example/datacacheput-unlocking-key-77158.aspx)。
So basicly I only have access to these methods:
value GetAndLock(key, out DataCacheLockHandle);
void PutAndUnlock(key, value, DataCacheLockHandle);
void Unlock(key, DataCacheLockHandle);
麻烦的是," GetAndLock"如果我尝试获取缓存中已有的内容,则抛出异常。同时,我在缓存中添加内容的唯一方法是" PutAndUnlock",除非我做了成功的" GetAndUnlock"否则不能使用它。
实际上,不可能在缓存中添加任何新东西,只有可以完成的事情就是替换已经存在的东西(这将是什么都没有)。
所以在我看来,我被迫使用乐观的" Put"在" GetAndLock"什么都没有抛出异常。根据我所读到的,乐观的" Put"销毁使用" GetAndLock"实现的任何现有锁定,这样就会破坏线程安全的整个尝试。
Example plan:
1. Try to GetAndLock
2. In case of nothing there exception:
- Put a dummy item on the key.
- GetAndLock again.
3. We have a lock, do computations, query database etc
4. PutAndUnlock the computed value
One of probably several ways it would screw up:
Thread1: Tries to GetAndLock, gets nothing there exception
Thread2: Tries to GetAndLock, gets nothing there exception
Thread1: Put a dummy item on the key
Thread1: GetAndLock again, lock achieved
Thread2: Put a dummy item on the key (destroying Thread1:s lock)
Thread2: GetAndLock again, lock achieved
Thread1: We think we have a lock, do computations, query database etc
Thread2: We have a lock, do computations, query database etc
Thread1: PutAndUnlock the computed value (will this throw an exception?)
Thread2: PutAndUnlock the computed value
基本上,两个线程可以同时向同一个键写入不同的东西,忽略他们认为已有的锁。
我唯一的结论可能是DataCache的悲观锁定功能不完整且完全无法使用。我错过了什么吗?有办法解决这个问题吗?
我失踪的是一种在存储任何内容之前预先锁定密钥的方法。
答案 0 :(得分:0)
乔纳森,
你是否考虑过将这些逻辑添加到缓存中(请原谅我的伪代码)?
public bool AddToCache(字符串键,对象值){
DataCache dc = _factory.GetDefaultCache();
object currentVal = dc.Get(key);
if (currentVal == null) {
dc.Put(key, value);
currentVal = dc.GetAndLock(key);
if (value == currentVal) {
//handle this rare occurrence + unlock.
return false;
} else {
dc.Unlock(key);
}
} else {
currentVal = dc.GetAndLock(key);
dc.PutAndUnlock (key, value);
}
return true;
}