x.wait ()
buffer.add (event)
mutex.signal ()
items.signal ()
Лістинг. 6 Покращене рішення виробника
Тепер ми можемо не турбуватися розблокувати споживача, поки не знатимемо, що робота може бути продовжена (крім того рідкісного випадку, коли інший виробник захопить м'ютекс).
Однак у цьому рішенні є проблема. Семафор items відстежує число елементів в черзі. Поглянувши на код споживача, ми бачимо, що є ситуація, в якій кілька споживачів поступово можуть зменшити items, перш ніж один з них захопить м'ютекс і видалить змінну з буфера. Принаймні, на деякий час items була б неточною. p align="justify"> Ми могли б спробувати вирішити цю проблему за коштами перевірки буфера всередині мьютекса.
mutex.wait ()
items.wait ()
event = buffer.get ()
mutex.signal ()
event.process ()
Лістинг. 7 Порушене рішення споживача
Однак, це рішення погане.
4. Deadlock # 4
Якщо споживач почне виконання коду, це може призвести до блокування.
mutex.wait ()
items.wait ()
event = buffer.get ()
mutex.signal ()
event.process ()
Лістинг. 8 Порушене рішення споживача
Уявімо собі, що буфер порожній. Споживач приходить, захоплює м'ютекс, а потім блокується на items. Коли прийде виробник, він заблокується на м'ютексів, що призведе до зупинки системи. p align="justify"> Це загальна помилка в коді синхронізації: якщо завжди чекати захоплення семафора, коли утримується м'ютекс, то існує небезпека настання deadlock. При вирішенні проблеми синхронізації потрібно обов'язково враховувати цей нюанс. br/>
. Виробник - споживач з кінцевим буфером
У прикладі вище описаний метод обробки подій потоками з використанням нескінченного буфера (розмір обмежений тільки фізичними ресурсами).
Проте в ядрі операційної системи існує ліміт на вільне місце. Для таких речей, як запити до дисків, мережеві пакети, буфер як правило має фіксований розмір. У подібних ситуаціях у нас є додаткове обмеження синхронізації. p align="justify"> Якщо виробник приходить, коли буфер повний, він блокується, поки споживач не видаляє елемент.
Припустимо ми знаємо розмір буфера. Назвемо його BufferSize. Тепер ми маємо семафор, який відстежує число елементів. Це можна спробувати представити так:
1 if items> = bufferSize:
block ()