在Microsoft.ApplicationServer.Caching.DataCache中添加一个带有悲观锁定的项
本文关键字:一个 悲观 锁定 Caching ApplicationServer Microsoft DataCache 添加 | 更新日期: 2023-09-27 18:03:26
我正在服务器端的web服务器上开发缓存层,使用Azure共享缓存,以减少对数据库的请求量,从而使程序运行得更快(希望如此)。我卡住的是如何使整个en吞食线程安全。我似乎没有找到一个可靠的和可用的方式来锁定密钥在数据缓存。我所缺少的是一种方法,可以在有任何存储在其中之前预先锁定键,这样我就可以添加一个值,而不会有另一个线程同时尝试做同样的事情的风险。
到目前为止,我一直只关注悲观锁定,因为这是线程安全对我最有意义的方式,我想确保我正在处理的东西是锁定的。
我已经明白,如果我要使用悲观锁定,我有责任只使用与之相关的方法。把这些东西混在一起会搞乱整个锁定机制(来源: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"抛出nothing there异常的情况下使用乐观的"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是功能不完整和完全不可用的。我错过什么了吗?有办法解决这个问题吗?
我所缺少的是一种方法,可以在有任何东西存储之前预先锁定密钥
Jonathan,
您是否考虑过将这种逻辑添加到缓存中(请原谅我的伪代码)?
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;
}