Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
СПОС_Конспект.doc
Скачиваний:
39
Добавлен:
02.05.2019
Размер:
1.13 Mб
Скачать

5. 3 Базові механізми синхронізації потоків

Сучасні ОС надають широкий набір готових механізмів синхронізації.

Механізмами синхронізації є засоби операційної системи, які допомогають розв’язувати основне завдання синхронізації – забезпечувати координацію потоків, котрі працюють зі спільно використовуваними даними. Якщо оакі засоби – це мінімальні блоки для побудови багатопотокових програм, їх називають синхронізаційними примітивами.

Синхронізаційні примітиви поділяють на такій основні категорії:

  • універсальні, низького рівня, які можна використовувати різнимииспособами (семафори);

  • прості, низького рівня, кожен з яких пристосований до розв’язання тільки одеієї задачі (мютекси та умовні змінні);

  • універсальні високого рівня, виражені через прості; до цієї групи належить концепція монітора, яка може бути виражена через м’ютекси та умовні змінні;

  • високого рівня, пристосовані до розв’язання конкретної синхронізаційної задачі (блокування читання-записування і бар’єри);

Розглянемо різні механізми і дамо оцінку перевагам, які має кожен з них, а також можливі їхні недоліки.

Для подальшої ілюстрації матеріалу візьмемо класичний пример, який демонструє необхідність синхронізації – задачу виробників-споживачів (produser-consumer problem) або задачу обмеженого буфера (bounded buffer).

Формулювання задачі просте. Припустимо, що в нас є потоки-виробники і потоки-споживачі. Виробник створює об’єкти, споживач їх отримує. Завданням є так синхронізувати їхню роботу, щоб споживач не міг намагатися отримувати ще не створені об’єкти, а виробник не міг створити більше об’єктів, ніж сможе отримати споживач.

Для синхронізації потоків помістимо між виробником і споживачем буфер фіксованої довжини n. Виробник може поміщати об’єкти у буфер, споживач – забирати їх звідти.Якщо споживач забирає об’єкт, його вилучають із буфера. Необхідно забезпечити кілька вимог:

  1. Коли виробник або споживач працює із буфером, решта потоків повинна чекати, поки він завершить свою роботу.

  2. Коли виробник намагається помістити об’єкт у буфер, а буфер повний (у ньому n об’єктів), він має дочекатися, поки в ньому з’явиться місце.

  3. Коли споживач намагається забрати об’єкт із буфера, а буфер порожній, він має дочекатися, поки в ньому з’явиться об’єкт.

5. 3. 1 Семафори

Концепцію семафорів запропонував у 1965 році Е. Дейкстра – відомий голландський фахівець у галузі комп’ютерних наук. Семафори є найстарішими синхронізаційними примітивами з числа тих, які застосовуються на практиці.

Семафор – це спільно використовуваний невід’ємний цілочисловий лічильник, для якого задано початкове значення і визначено такі атомарні операції:

  • Зменшення семафора (down): якщо значення семафора більш від нуля, його зменшують на одиницю, якщо ж значення дорівнює нулю, цей потік переходить у стан очікування доти, поки воно не стане більш від нуля (кажть, що потік “очікує на семафорі” або “заблокований на семафорі”). Таку операцію називають також очікуванням – wait. Ось її псевдокод:

void down(semaphore_t sem)

{

if (sem>0)

sem--;

else sleep();

}

  • Збільшення семафора (up): значення семафора збільшують на одиницю; коли прицьому є потоки, які очікують на семафорі, один із них виходить із очікування і виконує свою операцію down. Якщо на семафорі очікують кілька потоків, то внаслідок виконання операції up його значення залишається нульовим, але один із потоків продовжує виконання (у більшості реалізацій вибір цього потоку буде випадковим). Цюоперацію також назтвають сигналізацією – post. Ось її псевдокод:

void up(semaphore_t sem)

{

sem++;

if(waiting_threads())

wakeup(some_thread);

}

Фактично значення семафора визначає кількість потоків, що може пройти через цей семафор без блокування. Коли для семафора задане нульове прчаткове значення, то він блокуватиме всі потоки доти, поки якийсь потік його не “відкриє”, виконавши операцію up. Операції up і down можуть бути виконані будь-якими потоками, що мають доступ до семафора.

Дейкстра використовував для операції down позначення P (від голландського probirien – перевіряти), а для операції up – позначення V (від голландського verhoren – збільшувати). Ці позначення часто використовують у літературі.