为什么在Redis源代码中我没有看到内存障碍?

时间:2013-01-06 09:21:14

标签: c memory gcc redis kernel

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

但是在redis的来源中,我没有看到它。在redis的Makefile中,gcc optimize选项是-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()。它只是改变了线程堆栈空间中分配的变量,也改变了r / w操作之间的用户mb()。所以它不应该完全相关到多线程......(虽然redis是单线程)

2 个答案:

答案 0 :(得分:5)

认识到很少的代码需要明确的内存障碍可能会有所帮助。这些代码的一些示例包括OS内核,线程库和无锁数据结构。

大多数其他代码都是:

  1. 不直接与线程交互,不必使内存屏障;
  2. 使用操作系统提供的线程库(例如pthreads),并依赖此类库提供的memory ordering guarantees
  3. 如果在提出此问题时,您考虑到了Redis代码库的特定部分,请向我们展示相关代码。

答案 1 :(得分:5)

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

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