2

在 Linux 内核源代码中,存在许多内存屏障(smp_mb() 等)。

但是在redis的源码中,并没有看到。在redis的Makefile中,gcc优化选项是-O2,所以应该对这些指令重新排序。为什么它不使用 mb() 来确保正确的行为?

添加:

例如:在 Linux 内核的 kfifo 中:

unsigned int __kfifo_put(struct kfifo *fifo,unsigned char *buffer, unsigned int len)   
{   
  unsigned int l;   
  len = min(len, fifo->size - fifo->in + fifo->out);
  smp_mb();
  l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));   
  memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
  ...
  smp_wmb();
  fifo->in += len;
  ...
}

在 Redis 源码中,我研究了整个项目,找不到内存障碍:例如:

zskiplistNode *zslInsert(zskiplist *zsl, double score, robj *obj) {
  zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
  unsigned int rank[ZSKIPLIST_MAXLEVEL];
  int i, level;
  ...
  level = zslRandomLevel();
  if (level > zsl->level) {
    for (i = zsl->level; i < level; i++) {
      rank[i] = 0;
      update[i] = zsl->header;
/////need a mb() ???
      update[i]->level[i].span = zsl->length;
    }
    zsl->level = level;
  }
  ...
}

为什么在redis中没有内存屏障有什么特别的吗?
我认为我对 mb() 的理解可能不成熟,感谢您的评论...

添加:

但是在上面显示的两段代码中,linux内核中的kfifo使用了mb()。它只是更改分配在线程堆栈空间中的变量以及用户 mb() 在 r/w 操作之间。所以它不应该完全与多线程相关......(虽然redis是单线程)

4

2 回答 2

6

意识到很少的代码需要显式的内存屏障可能会有所帮助。此类代码的一些示例包括操作系统内核、线程库和无锁数据结构。

大多数其他代码将:

  1. 不直接与线程交互,使内存屏障变得不必要;
  2. 使用操作系统提供的线程库(例如pthreads),并依赖此类库提供的内存排序保证。

如果在问这个问题时,您想到了 Redis 代码库的特定部分,请向我们展示相关代码。

于 2013-01-06T09:32:45.627 回答
6

Redis 是单线程的,因此不需要内存屏障。

只有当您有多个执行路径(例如在多线程应用程序中)时,它们才有意义。即使使用多线程用户空间应用程序,您通常也不需要自己的内存屏障,因为库(例如 pthreads)在同步 API 中包含内存屏障(例如互斥锁、信号量、条件变量等)。

于 2013-01-06T16:23:50.960 回答