【发布时间】:2013-01-06 09:21:14
【问题描述】:
在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是单线程)
【问题讨论】:
-
这个问题太模糊了。具体来说,请展示一些您认为需要内存屏障才能正确操作但没有使用内存屏障的 Redis 代码。
-
我对 Redis 的代码库一无所知。是否有理由认为您展示的跳过列表实现是线程感知的,更不用说线程安全了?
-
在Multi-Processing(SMP..)中,如果用gcc打开优化,可能会重新排序指令。所以它可能是 CPU 从存储缓冲区读取/写入脏数据,所以需要 mb() 来确保正确的行为? (在我看来)
-
好吧,如果只有一个线程查看/更改数据,那么所有这些都是完全无关的。不允许编译器以会破坏单线程代码的方式重新排序指令。
-
那些数据在线程堆栈上,我认为它与线程无关,但与共享数据上的多 CPU 操作有关