2013-01-06 72 views
2

在Linux內核源代碼中,有很多內存屏障(smp_mb()等)。爲什麼在Redis源代碼中我沒有看到內存障礙?

但在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() 。它只是改變線程堆棧空間中分配的變量以及r/w操作之間的用戶mb()。所以它不應該完全相關於多線程......(雖然redis是單線程的)

+2

這個問題太含糊。爲了使其具體,請顯示一些您認爲需要內存屏障才能正確操作的Redis代碼,但不使用它。 – NPE

+0

謝謝,我重新編輯它 –

+0

我對Redis的代碼庫一無所知。是否有理由認爲您展示的跳過列表實現意味着線程感知,讓線程安全? – NPE

回答

5

Redis是單線程的,所以不需要內存障礙。

它們只在您有多個執行路徑(例如,在多線程應用程序中)時才相關。即使使用多線程用戶空間應用程序,由於庫(例如pthread)在同步API中包含內存屏障(例如互斥鎖,信號量,條件變量等),您通常不需要自己的內存屏障。

+0

但是在上面顯示的兩段代碼中,linux內核中的kfifo使用了mb()。它只是改變線程堆棧空間中分配的變量以及r/w操作之間的用戶mb()。所以它不應該完全相關於多線程... –

+1

@Pei WenQian不,它不。它從傳入的struct kfifo中讀取和寫入,struct kfifo可以在內核中的幾個不同任務之間共享,因此代碼需要關注fifo的併發使用,但在某些情況下,您需要爲__kfifo_put額外鎖定。 – nos

+0

哦!是的,我偏重於len參數,這些mb()不用於同步len,針對struct kfifo。非常感謝 –

5

認識到很少的代碼需要顯式的內存屏障可能會有幫助。這些代碼的一些例子包括OS內核,線程庫和無鎖數據結構。

大多數其他代碼要麼:

  1. 不直接與螺紋相互作用,使得存儲器不必要的障礙;
  2. 使用OS提供的線程庫(例如pthreads),並依賴於由這樣的庫提供的memory ordering guarantees

如果在問這個問題時,你有一個Redis代碼庫的特定部分,請告訴我們相關的代碼。

+0

非常感謝,我重新編輯它。這是我第一次問stackoverflow的問題,請原諒我的疏忽 –

相關問題