繁体   English   中英

C ++的缓存锁定模式

[英]Cache locking pattern with C++

我想知道是否有比简单锁更好的缓存锁定方案:

Mutex lock;
get(key) {
  LockGuard(lock);

  if (cache.has(key)) {
    return cache[key];
  } else {
    data = remoteclient.getslow();
    cache[key] = data;
    return data;
  }
}

假设您有很多相同的请求,那么您每次都会序列化对get()的访问。 可以用ReadWriter锁来做一些更聪明的事情吗?

即,如果您做类似的事情:

ReadersWritersLock lock;
get(key) {
  {
    ReadLockGuard(lock);
    if (cache.has(key)) {
      return cache[key];
    } 
  }
  WriteLockGuard(lock);
  data = remoteclient.getslow();
  cache[key] = data;
  return data;
 }
}

现在,如果发生缓存命中,这将允许多个用户同时获取get()。 但是,如果两个用户大约在同一时间到达第一个get(),则他们可能都将尝试进入代码的第二部分来获取数据。 这似乎是个好主意吗?

还有其他想法可以优化这种代码吗?

我对发布的代码不满意的一件事是在两个代码段中

remoteclient.getslow();

在缓存被锁定时调用。 如果remoteclient.getslow()实际上可能需要很长时间才能返回(顾名思义),则任何其他尝试访问缓存的线程最终都会被阻塞很长时间(即,直到getslow()返回并且即使他们只对缓存中已经存在的无关数据感兴趣,调用它的线程也会释放锁!

为了避免这种情况,我会改为在LockGuard范围之外(即,在解锁缓存时)调用remoteclient.getslow()。 然后,在remoteclient.getslow()返回结果之后,我将重新锁定缓存并使用检索到的值更新缓存。 这样,缓存就不会长时间锁定。

(当然,这样做会打开多个线程为同一数据项调用remoteclient.getslow()的可能性,如果它们都决定在大约同一时间都需要相同的数据……但这是可以接受的。否则,您可以设计一种机制来指示正在检索特定的高速缓存值,并使其他线程处于阻塞状态,直到检索完成为止……如果那对您来说值得额外的复杂性。那可能需要条件变量之类的东西才能正确执行)

您的伪代码有正确的主意,但是有竞争条件。

一旦ReadLockGuard超出范围,您就会丢失锁,这意味着在WriteLockGuard有时间获取锁之前,可以由另一个线程修改数据结构。

如果您的读取器/写入器锁实现支持可升级的锁,则应使用该锁。 否则,在获取写锁之后,您需要仔细检查缓存,以防缓存填充在“读取器”发行版和“写入器”发行版之间。

两个线程可能会进入get()的“写入”部分,但可能性很小。 如果您担心额外的getslow()调用的代价,则可以在writer锁内再次检查。

ReadersWritersLock lock;
get(key) {
  {
    ReadLockGuard(lock);
    if (cache.has(key)) {
      return cache[key];
    } 
  }
  WriteLockGuard(lock);
  if (cache.has(key) == false) {
    data = remoteclient.getslow();
    cache[key] = data;
    return data;
  }
 }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM