【问题标题】:Adding an item to Microsoft.ApplicationServer.Caching.DataCache with pessimistic locking?使用悲观锁定向 Microsoft.ApplicationServer.Caching.DataCache 添加项目?
【发布时间】:2013-03-12 14:43:15
【问题描述】:

我正在服务器端的 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 的悲观锁定是功能不完整,完全无法使用。我错过了什么吗?有没有办法解决这个问题?

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

【问题讨论】:

  • GetAndLock 具有参数forceLock,其中 msdn 表示:如果 forceLock 为真,则无论缓存中是否存在键值对,都会锁定键。即使该键的状态不存在,这也不能帮助您锁定键吗?

标签: c# azure locking pessimistic-locking


【解决方案1】:

乔纳森,

您是否考虑过这种向缓存添加内容的逻辑(请原谅我的伪代码)?

public bool AddToCache(string key, object value) {

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;

}

【讨论】:

  • 我不确定我是否完全关注。你的意思是添加一些代码来处理锁被中断的情况吗?
  • 嗯,再读一遍,我猜你不是那个意思。使用 Get 检查密钥是否不存在的问题在于,另一个线程可能会在您工作时执行相同的操作,因此您可以使用两个并行线程执行 Put。这个 Put 可能会破坏另一个线程的获取的 GetAndLock。
  • 这个想法是: 1. 做一个 get 看看它是否存在 2. 如果它不存在添加它 3. 再次检查它(带锁) 4. 如果新值存在不等于您刚刚添加的值,然后其他线程在您检查值是否存在和锁定它之前对其进行了更改-->因此您必须添加一些逻辑来处理这种情况。
  • 我明白了。我相信这也可能失败,但方式不同。线程 1:检查获取线程 2:检查获取线程 1:是否放置线程 3:检查获取线程 1:锁定以检查值是否更改,它没有 线程 1:解锁 线程 3:currentVal 是不为null,正常情况下Lock Thread 2:做Put,破坏线程3的Lock
  • 也就是说,我现在确实有一个计划,我主要编写了一个计划,但它还不是没有错误的。当我认为是时,我会发布它。一般的想法是我在应用程序启动时向缓存添加一个虚拟项目,这样我就有了我知道我可以锁定的东西,然后我将它用作整个缓存的一种金属锁,以允许检查和添加不间断。
猜你喜欢
  • 1970-01-01
  • 2010-09-12
  • 1970-01-01
  • 1970-01-01
  • 2014-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多