2015-08-26 1 views
0

Я пытаюсь разработать приложение с одним производителем и несколькими потребителями. Производители - это один процесс, и каждый потребитель - это один процесс. Общий ресурс - это своего рода буфер в общей памяти.Неблокирующий производитель разделяемой памяти, использующий условие форсированного интерпроцесса для уведомления

Производитель должен работать полностью независимо от потребителей. В любом случае его нельзя блокировать. Поэтому потребители несут ответственность за проверку достоверности данных, которые они считывают из общей памяти, и обрабатывают их, если производитель уже перезаписал данные. (Они делают это с использованием какого-то хеширования. Не важно.)

Потребители должны быть проинформированы о наличии новых данных в буфере. Я думаю, что условия для промежуточного процесса подходят для этой утилиты. (Более подходящими были бы сигналы boost2, но эта библиотека не работает в режиме interprocess).

Условие всегда требует мьютекса. Но мне не нужен мьютекс в моем продюсере. В потребителя мне нужно только мьютекс для условия # wait.

Можно ли использовать кодировку # notify_all только в коде производителя и не использовать мьютексы? Или это злоупотребление библиотекой?

Заранее спасибо

+0

Почему бы вам не использовать трубу/FIFO, которую читают потребители, и производители пишут? Вам не пришлось бы иметь дело с синхронизацией, и это значительно упростило бы дизайн. –

+0

Я использую какой-то ФИФО. Но я хочу получать уведомления, когда новые данные доступны в FIFO. – hami

+0

Неблокирование и уведомление о состоянии - это противоречия. – sehe

ответ

0

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

Сигнализации под мьютексом гарантирует справедливое планирование официантов под POSIX, насколько я знаю, ¹

То есть, я думаю, что комментаторы правы, когда они чувствуют запах overcomplication в дизайне. Я бы упростил. Оптимизируйте, когда вам это нужно.

¹ См., Например, здесь: http://linux.die.net/man/3/pthread_cond_signal

В pthread_cond_broadcast() или pthread_cond_signal() функций могут вызываться нитью или нет в данный момент владеет мьютексом, что потоки призывающей pthread_cond_wait() или pthread_cond_timedwait() ассоциировали с переменным состоянием во время их ждут; однако, если требуется предсказуемое поведение при планировании, то мьютекс должен быть заблокирован потоком, вызывающим pthread_cond_broadcast() или pthread_cond_signal().

0

Производитель должен работать полностью независимо от потребителей. В любом случае он не должен быть заблокирован .

Почему нет? Это не должно влиять на производительность, если вы не блокируете слишком часто. У вас может быть счетчик данных в общей памяти, и вы заблокируете доступ только к этому счетчику. Данные могут храниться в кольцевом буфере в разделяемой памяти, и доступ к ней не нужно блокировать, потому что потребители проверяют, сколько данных доступно для чтения с использованием счетчика. Конечно, потребители должны быстро читать данные. Если данные перезаписаны, то внутренний счетчик потребителей может быть сброшен на значение счетчика межпроцессорных операций.

Также производитель может хранить данные, используя много потоков. Каждый поток может рассчитать будущую позицию данных в начале потока и затем обновить счетчик после того, как данные будут сохранены в конце потока. Затем требуется дополнительная блокировка для будущих расчетов местоположения, чтобы это значение могло быть передано между потоками.

В деталях, не-многопоточный сценарий может работать следующим образом:

Producer loop: 
    receive X samples of data 
    lock access to interprocess counter, increment the counter, unlock the access 

Тогда каждый потребитель имеет свой собственный внутренний счетчик, так что он может сравнить межпроцессорный счетчиком, если и сколько данных доступно для чтения (просто опрос для данных):

Consumer loop: 
    lock access to interprocess counter, read the counter value, unlock the access 
    compare the read value with internal counter 
    if values equal // no data available 
    sleep, then continue to the beginning of the loop 
    else if data overwritten // no need for hashing here, counter can be use to figure that out although doing it this way is probably a bit risky 
    set internal counter to the value of the interprocess counter 
    then continue to the beginning of the loop 
    else 
    read available data 
    increment internal counter