2011-12-27 4 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

Не используйте глобальную переменную для достижения своей цели, особенно в многопоточном приложении !!! Вместо этого используйте Семафор и не делайте 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

Вы можете достичь функциональности TryLock передачей 0 в качестве тайм-аута для функции WaitForSingleObject.

+0

Я использую глобальные переменные и атомарные операции для выполнения синхронизации беззамочной. Это по соображениям производительности. – rnd

+0

Ну ... на самом деле у вас есть только инкремент. У вас все еще есть буфер [i] .bNew грязный. На мой взгляд, использование единого семафора - это лучшая идея, а не назначение производителей одному индексу узла массива. – SOReader

0

Пожалуйста, прочтите это: http://en.wikipedia.org/wiki/Memory_barrier

Стандарты C и C++ не обращаются несколько потоков (или несколько процессоров), и, как таковые, полезность летучий зависит от компилятора и аппаратного обеспечения. Несмотря на то, что волатильность гарантирует, что волатильные будут считаться и волатильные записи будут происходить в точном порядке, указанном в , исходный код, компилятор может генерировать код (или CPU может выполнить повторное выполнение), чтобы измененное считывание или запись переупорядочивалось в отношении энергонезависимых чтений или записей, что ограничивает его полезность в качестве флага или мьютекса между потоками. Более того, это не гарантирует, что волатильные чтения и записи будут видны в том же порядке другими процессорами из-за кэширования, протокола когерентности кэш-памяти и упорядоченного упорядочения памяти, что означает, что только изменчивые переменные могут даже не быть работать как межпоточные флаги или мьютексы.

Таким образом, в общем случае, просто летучий не будет работать на C. Но она могла бы работать для некоторых конкретных компиляторов/аппаратных и других языков (Java, например, 5).

Смотрите также Is function call a memory barrier?

+0

Прежде всего, блокированные операции помещают барьер памяти. Вторая проблема заключается в том, что я компилирую ее на x86, где защита памяти не нужна (например, MemoryBarrier имеет пустое тело) – rnd

+0

А как насчет многоядерных кешей? – Vadzim

+0

На x86 все обновления отображаются на других ядрах в порядке записи. Этого достаточно, чтобы предотвратить переупорядочение. Но я думаю, что поле контента также должно быть изменчивым, поэтому, вероятно, это моя ошибка. – rnd

Смежные вопросы