program sem_example (* захист ресурсу *) var P1: semaphore begin b> P1:=1; cobegin while true do (* нескінченний цикл *) begin (* процес А *) wait (P1); (* Захищений ресурс *) signal (P1); ... end ; (* Процес А *) while true do (* нескінченний цикл *) begin (* процес В *) wait (Pl); (* Захищений ресурс *) signa l (Pl); ... end; (* процес В *) coend ; end . (* Sem_example *) Семафор гарантує, що два процеси можуть отримати доступ до захищеного ресурсу тільки по черзі.
При цьому не створюється ніяких додаткових зв'язків - якщо один процес виповнюється швидше іншого, то за певний проміжок часу він буде частіше отримувати доступ до ресурсу. Процес вимушений чекати закінчення іншого тільки в тому випадку, коли останній перебуває у критичній секції. Одночасно гарантується і живучість. Якщо виконання процесу з якихось причин припиняється, то, за умови, що він знаходився поза критичної секції, це не заважає розвитку іншого процесу.
Саме по собі застосування семафорів не гарантує запобігання тупикових ситуацій. Якщо два процеси використовують семафори наступним чином wait (Pl) wait (P2) wait b> (P2) wait (Pl) ...... (* захищений ресурс *) (* захищений ресурс *) ...... signal (Pl) signa l (P2) signal (P2) signal ( Pl) то як і раніше існує ризик виникнення тупика. Якщо перемикання процесів відбувається між двома операторами wait першої програми, а друга програма виконає свої оператори wait , то це призводить до глухого кута, оскільки кожна програма очікує від іншої звільнення семафора.
Проблема полягає в тому, що, хоча семафор гарантує нерозривність перевірки та встановлення значення, він сам залишається захищеним ресурсом. У наведеному прикладі явно порушена заборона послідовного виділення, і це призводить до можливості тупикових ситуацій. Семафор може допомогти при синхронізації взаємопов'язаних дій. Наприклад, якщо процес повинен працювати з даними тільки після того, як вони лічені з зовнішнього порту, програма може мати наступний вигляд: Process «Читання даних» Process «Обробка даних» while true do while true do begin begin (* читання нових даних *) wait b> (data_available); signal (data_available); (* Обробка даних *) end; end; Це решение відокремлює операцію введення даних від їх обробки. На появу нових даних вказує значення семафора, відмінне від 0. Якщо існує механізм буферизації (проміжного зберігання) нових даних, то процедура обробки зможе отримати всі дані, навіть якщо вони надходять швидше, ніж вона в змозі їх прийняти. У системах реального часу прийнято відокремлювати процедури, які потребують швидкої реакції, наприклад прийом даних з зовнішнього порту, від інших пр...