Лекція: Примітиви синхронізації: семафори та м'ютекси
Вступ
У сучасних операційних системах існує можливість одночасного виконання кількох процесів або потоків. Це може призводити до ситуацій, коли кілька потоків намагаються отримати доступ до спільних ресурсів одночасно, що створює ризик виникнення помилок та некоректної роботи програм. Для запобігання таким ситуаціям використовуються примітиви синхронізації, такі як семафори та м'ютекси. Ці інструменти дозволяють регулювати доступ до спільних ресурсів, забезпечуючи коректне виконання багатопотокових програм.
Метою цієї лекції є ознайомлення з поняттями семафорів і м'ютексів, їх принципами роботи, а також застосуванням у вирішенні задач синхронізації.
1. Що таке синхронізація?
1.1. Визначення
Синхронізація — це процес управління доступом до спільних ресурсів у багатопотоковому або багатозадачному середовищі. Вона запобігає виникненню конфліктів між потоками, які намагаються одночасно використовувати ті самі ресурси, такі як пам'ять, файли або периферійні пристрої.
1.2. Проблеми при відсутності синхронізації
Гонки (Race Conditions): виникають, коли кілька потоків одночасно змінюють спільний ресурс, що може призвести до некоректних результатів.
Взаємне блокування (Deadlock): ситуація, коли два або більше потоків чекають один на одного, щоб звільнити ресурс, що призводить до безкінечного очікування.
Голодання (Starvation): процес або потік не отримує доступу до ресурсу через пріоритет інших потоків.
2. Семафори
2.1. Визначення
Семафор — це примітив синхронізації, який використовується для управління доступом до спільних ресурсів шляхом використання лічильника. Семафор має дві основні операції:
P (Wait, Down): зменшує значення семафора на одиницю. Якщо результат негативний, потік блокується до тих пір, поки семафор не буде збільшено.
V (Signal, Up): збільшує значення семафора на одиницю. Якщо інші потоки очікують на ресурс, один із них буде розблокований.
2.2. Типи семафорів
Бінарний семафор (значення 0 або 1): використовується як взаємне виключення, аналог м'ютекса.
Лічильний семафор: може приймати будь-яке не негативне значення. Застосовується для обмеження доступу до певної кількості ідентичних ресурсів.
2.3. Приклад використання семафора
#include <semaphore.h>
#include <pthread.h>
sem_t semaphore;
void thread_function(void arg) {
sem_wait(&semaphore); // Очікування доступу
printf("Потік %ld виконується\n", (long)arg);
sem_post(&semaphore); // Звільнення доступу
return NULL;
}
int main() {
sem_init(&semaphore, 0, 1); // Ініціалізація семафора
pthread_t thread1, thread2;
pthreadcreate(&thread1, NULL, threadfunction, (void*)1);
pthreadcreate(&thread2, NULL, threadfunction, (void*)2);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
sem_destroy(&semaphore); // Звільнення ресурсів
return 0;
}
У цьому прикладі лише один потік може виконуватись у певний момент часу завдяки використанню семафора.
3. М'ютекси
3.1. Визначення
М'ютекс (mutual exclusion) — це примітив синхронізації, який використовується для забезпечення взаємного виключення. Він дозволяє лише одному потоку отримати доступ до критичної секції в будь-який момент часу. Якщо інший потік намагається захопити м'ютекс, він буде заблокований до тих пір, поки м'ютекс не буде звільнений.
3.2. Операції з м'ютексами
lock() — захоплює м'ютекс. Якщо він вже захоплений іншим потоком, поточний потік блокується.
unlock() — звільняє м'ютекс, дозволяючи іншим потокам отримати доступ до ресурсу.
3.3. Приклад використання м'ютекса
#include <pthread.h>
#include <stdio.h>
pthreadmutext mutex;
int counter = 0;
void increment(void arg) {
pthreadmutexlock(&mutex); // Захоплення м'ютекса
counter++;
printf("Counter: %d\n", counter);
pthreadmutexunlock(&mutex); // Звільнення м'ютекса
return NULL;
}
int main() {
pthread_t thread1, thread2;
pthreadmutexinit(&mutex, NULL);
pthread_create(&thread1, NULL, increment, NULL);
pthread_create(&thread2, NULL, increment, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
pthreadmutexdestroy(&mutex);
return 0;
}
У цьому прикладі два потоки збільшують значення лічильника counter, але завдяки м'ютексу вони не можуть зробити це одночасно.
4. Порівняння семафорів та м'ютексів
Характеристика | Семафор | М'ютекс |
|---|---|---|
Значення | Може мати значення > 1 | Тільки 0 або 1 |
Використання | Синхронізація кількох потоків | Взаємне виключення |
Власник | Відсутній | Потік, що захопив м'ютекс |
Застосування | Лічильник доступних ресурсів | Блокування критичних секцій |
5. Проблеми при використанні примітивів синхронізації
Взаємне блокування (Deadlock): потоки чекають на ресурси, які захоплені один одним.
Голодання (Starvation): низькопріоритетні потоки не отримують доступу до ресурсів.
Завищене використання процесора (Busy Waiting): деякі реалізації м'ютексів можуть використовувати активне очікування, що призводить до марнування процесорного часу.
Для уникнення цих проблем використовуються складніші механізми, такі як умовні змінні, монітори, чекові алгоритми.
Висновок
Примітиви синхронізації, такі як семафори та м'ютекси, є основними інструментами для управління доступом до спільних ресурсів у багатопотокових програмах. Вони допомагають уникнути проблем, пов'язаних із гонками та конфліктами, забезпечуючи коректне виконання програм. Вибір між семафорами і м'ютексами залежить від специфіки завдання: для простого взаємного виключення зазвичай використовують м'ютекси, тоді як семафори підходять для управління доступом до ресурсів із обмеженою кількістю.
Питання для вихідного контролю
Що таке синхронізація і навіщо вона потрібна?
Яка різниця між семафором і м'ютексом?
Поясніть операції P (Wait) і V (Signal) у семафорі.
Як працює м'ютекс? Наведіть приклад використання.
Що таке гонки (Race Conditions) і як їх уникнути?
Що станеться, якщо потік не звільнить м'ютекс?
Які основні типи семафорів існують?
У яких ситуаціях доцільно використовувати лічильний семафор?
Що таке взаємне блокування (Deadlock) і як його уникнути?
Наведіть приклади реального застосування семафорів та м'ютексів.
Ці питання допоможуть перевірити розуміння матеріалу та підготуватися до практичних завдань на тему синхронізації потоків.















