3

我正在服务器端的 Web 服务器上的缓存层上工作,使用 Azure 共享缓存来减少对数据库的请求量,从而使东西运行得更快(希望如此)。我遇到的问题是如何使整个 endevour 线程安全。我似乎没有找到一种可靠且可用的方法来锁定 DataCache 中的键。我缺少的是一种在密钥上存储任何内容之前预先锁定密钥的方法,这样我就可以添加一个值,而不会有另一个线程同时尝试做同样的事情的风险。

到目前为止,我一直只关注悲观锁定,因为这就是线程安全对我来说最有意义的方式,我想确保我正在处理的东西被锁定。

我明白,如果我要使用悲观锁定,我只负责使用与此相关的方法。混合使用会弄乱整个锁定机制(来源: 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”,否则无法使用该方法。

实际上,不可能向缓存中添加任何新内容,唯一可以做的就是替换已经存在的内容(这将一事无成)。

所以在我看来,在“GetAndLock”抛出异常的情况下,我被迫使用乐观的“Put”。但是,根据我所读到的内容,乐观的“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 的悲观锁定是功能不完整,完全无法使用。我错过了什么吗?有没有办法解决这个问题?

我所缺少的只是一种在钥匙上存储任何东西之前抢先锁定钥匙的方法。

4

1 回答 1

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;

}

于 2013-03-15T02:24:09.523 回答