2011-12-27 103 views
1

我有生產者消費者問題需要稍加修改解決 - 有許多並行生產者,但只有一個消費者在一個並行線程。當製片人沒有放置緩衝區時,它就會忽略元素(不等待消費者)。我有一些C編寫的僞代碼:幾乎無鎖生產者消費者

struct Element 
{ 
    ULONG content; 
    volatile LONG bNew; 
} 

ULONG max_count = 10; 
Element buffer* = calloc(max_count, sizeof(Element)); 
volatile LONG producer_idx = 0; 
LONG consumer_idx = 0; 
EVENT NotEmpty; 

BOOLEAN produce(ULONG content) 
{ 
    LONG idx = InterlockedIncrement(&consumer_idx) % max_count; 

    if(buffer[idx].bNew) 
    return FALSE; 
    buffer[idx].content = content; 
    buffer[idx].bNew = TRUE; 
    SetEvent(NotEmpty); 
    return TRUE; 
} 

void consume_thread() 
{ 
    while(TRUE) 
    { 
    Wait(NotEmpty); 
    while(buffer[consumer_idx].bNew) 
    { 
     ULONG content = buffer[consumer_idx].content; 
     InterlockedExchange(&buffer[consumer_idx].bNew, FALSE); 
     //Simple mechanism for preventing producer_idx overflow 
     LONG tmp = producer_idx; 
     InterlockedCompareExchange(&producer_idx, tmp%maxcount, tmp); 
     consumer_idx = (consumer_idx+1)%max_count; 
     doSth(content); 
    } 
    } 
} 

我不是100%確定這段代碼是正確的。你能看到可能發生的任何問題嗎?或者,也許這個代碼可以寫得更好?

回答

0

不要使用全局變量來實現您的目標,特別是在多線程應用程序中!改用Semaphore,而不要使用Lock,而是使用TryLock。如果TryLock失敗,則意味着沒有空間存放其他元素,因此您可以跳過它。

在這裏你能找到的東西在WinAPI的閱讀有關信號量,因爲你可能會使用它: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686946(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx

你可以通過0作爲超時WaitForSingleObject函數實現的tryLock功能。

+0

我使用全局變量和原子操作執行無鎖同步。這是出於性能原因。 – rnd 2011-12-27 11:10:34

+0

恩......實際上你只有增量安全。你仍然有緩衝[i] .b新的髒讀。在我看來,使用單個信號量是一個更好的主意,而不是將生產者分配給數組中的單個位置索引 – SOReader 2011-12-27 12:16:53

0

請閱讀此:http://en.wikipedia.org/wiki/Memory_barrier

C和C++標準沒有解決多個線程(或多個 處理器),並且同樣地,易失性的有用性取決於該 編譯器和硬件。儘管易失性保證易失性寫入和易失性寫入將按照源代碼 中指定的確切順序發生,但編譯器可能會生成代碼(或者CPU可能會重新排序執行),以便對易失性讀取或寫入進行重新排序。 關於非易失性讀取或寫入,因此限制其作爲線程間標誌或互斥體的用處。此外,由於緩存,緩存一致性協議和輕鬆的內存排序,這意味着易失性讀取和寫入將被其他處理器以相同的 順序看到,這意味着易失性變量本身甚至不可能作爲線程間標記工作或互斥體。

因此,在通常情況下只揮發不會爲C. 工作,但它可以爲某些特定的編譯器/硬件和其他工作語言(Java 5中,例如)。

又見Is function call a memory barrier?

+0

首先,互鎖操作會使內存屏障。第二個問題是我在不需要內存屏障的x86上編譯它(例如MemoryBarrier有空的主體) – rnd 2011-12-27 12:47:26

+0

那麼多核高速緩存怎麼樣? – Vadzim 2011-12-27 13:06:19

+0

在x86上,所有更新都以寫入順序在其他內核上顯示。如此不穩定就足以阻止重新排序。但我認爲內容領域也應該是不穩定的,所以這可能是我的錯誤。 – rnd 2011-12-27 13:37:55