
- •Урок № 61
- •Урок № 62
- •Урок № 72
- •Урок № 73
- •Створення зв'язку з файлом /dev/modem за допомогою команди lisa.
- •Настройка системи Linux для встановлення зв'язку.
- •Як створюється зв'язок з файлом /dev/modem за допомогою команди lisa?
- •Яким чином можна настроїти систему Linux для встановлення зв'язку?
- •Урок № 74
- •Урок № 75
- •Використання програми mail.
- •Урок № 76
- •Використання клієнта kpackage
- •Як використовується клієнт kpackage?
- •Урок № 77
- •Урок № 80
- •Урок № 82
- •Урок № 84
- •Урок № 85
- •Урок № 86
- •Урок № 87
- •Урок № 88
- •Урок № 89
- •Урок № 90
- •Урок № 92
- •Урок № 93
- •Урок № 95
- •Урок № 96
- •Урок № 97
- •Урок № 97
Урок № 95
(згідно навчальної робочої програми)
Тема: «Принципи та проблеми взаємодії потоків»
Питання:
Принципи взаємодії потоків.
Проблема змагання.
Поняття критичної секції.
Блокування.
Програмно-апаратна реалізація блокувань.
Потоки, які виконуються в рамках процесу паралельно, можуть бути незалежними або взаємодіяти між собою.
Потік є незалежним, якщо він не впливає на виконання інших потоків процесу, не зазнає впливу з їхнього боку, та не має з ними жодних спільних даних. Його виконання однозначно залежить від вхідних даних і називається детермінованим.
Усі інші потоки є такими, що взаємодіють. Ці потоки мають дані, спільні з іншими потоками (вони перебувають в адресному просторі їхнього процесу), їх виконання залежить не тільки від вхідних даних, але й від виконання інших потоків, тобто вони є недетермінованими.
Результати виконання незалежного потоку завжди можна повторити, чого не можна сказати про потоки, що взаємодіють.
Дані, які є загальними для кількох потоків, називають спільно використовуваними даними (shareddata). Усякий потік може в будь-який момент часу змінити такі дані. Механізми забезпечення коректного доступу до спільно використовуваних даних називають механізмами синхронізації потоків.
Працювати із незалежними потоками простіше, ніж із тими, що взаємодіють.
Причини реалізації взаємодії потоків :
Необхідно організовувати спільне використання інформації під час роботи з потоками.
Коректна реалізація такої взаємодії та використання відповідних алгоритмів можуть значно прискорити обчислювальний процес на багатопроцесорних системах. При цьому задачі розділяють на підзадачі, які виконують паралельно на різних процесорах, а потім їхні результати збирають разом для отримання остаточного розв’язання. Таку технологію називають технологією паралельних обчислень.
У задачах, що вимагають паралельного виконання обчислень та операцій вве-дення-виведення, потоки, що виконують введення-виведення, повинні мати можливість подавати сигнали іншим потокам із завершенням своїх операцій.
Подібна організація дає змогу розбивати задачі на окремі виконувані модулі, оформлені як окремі потоки, при цьому вихід одного модуля може бути входом для іншого, а також підвищується гнучкість системи, оскільки окремі модулі можна міняти, не чіпаючи інших.
Проблема змагання
Розглянемо основні підходи до розв’язання проблеми змагань.
Іноді можна просто ігнорувати такі помилки. Це може мати сенс, коли нас цікавить не точна реєстрація тих або інших даних, а збір статистики про них, тому окремі помилки не позначатимуться на загальному результаті.
Іноді використання глобальних даних не диктується специфікою задачі. У цьому разі однозначним розв’язанням є створення локальних копій цих даних для кожного потоку й оперування тільки ними. На практиці це працює вельми добре й має використовуватися, де тільки можливо.
У всіх інших випадках потрібно забезпечувати захист змін від впливу інших потоків. Це і є основним завданням синхронізації. Перейдемо до аналізу різних підходів до його розв’язання.
Поняття критичної секції
Розв’язанням проблеми змагання є перетворення фрагмента коду, який спричиняє проблему, в атомарну операцію, тобто в таку, котра гарантовано виконуватиметься цілковито без втручання інших потоків. Такий фрагмент коду називають критичною секцією(criticalsection):
// початок критичної секції
total_amount= tota1_amount+ new_amount;
// кінець критичної секції
Тепер, коли два потоки візьмуться виконувати код критичної секції одночасно, той з них, що почав першим, виконає весь її код цілком до того, як другий почне своє виконання.
Властивості критичної секції:
Взаємне виключення (mutual exclusion): у конкретний момент часу код критичної секції може виконувати тільки один потік.
Прогрес: якщо кілька потоків одночасно запросили вхід у критичну секцію, один із них повинен обов’язково у неї ввійти.
Обмеження очікування: процес, що намагається ввійти у критичну секцію, рано чи пізно обов’язково в неї ввійде.
Залишається відповісти на далеко не просте запитання: «Як нам змусити систему сприймати кілька операцій як одну атомарну операцію?»
Найпростішим розв’язанням такої задачі було б заборонити переривання на час виконання коду критичної секції. Такий підхід, хоча й розв’язує задачу в принципі, на практиці не може бути застосовуваний, оскільки внаслідок зациклення або аварії програми у критичній секції вся система може залишитися із заблокованими перериваннями, а отже, у непрацездатному стані.
Блокування
Раціональнішим розв’язанням є використання блокувань(locks). Блокування — це механізм, який не дозволяє більш як одному потокові виконувати код критичної секції. Використання блокування зводиться до двох дій: запровадження (заблокування, функція acquire_lоск ()) і зняття блокування (розблокування, функція release_lock()). У разі заблокування перевіряють, чи не було воно вже зроблене іншим потоком, і якщо це так, цей потік переходить у стан очікування, інакше він запроваджує блокування і входить у критичну секцію. Після виходу із критичної секції потік знімає блокування.
acquire_lock(lock):
// критична секція
Release_lock(lock):
Так реалізовують властивість взаємного виключення, звідси походить інша назва для блокування — м’ютекс(mutex, скорочення від mutualexclusion).
Програмно-апаратна реалізація блокувань
Заблокування і розблокування із використанням інструкції TSL (можна реалізувати так:
voidacquirejockdntlock) {
// якщо блокування немає (lock== 0). запровадити його (задати 1оск=1)
// і вийти - ми ввійшли у критичну секцію
// інакше чекати, поки блокування не знімуть, і не міняти lock
while (TSL(lock) != 0);
}
voidrelease_lock(int lock) {
// зняти блокування lock = 0:
}
Головним недоліком описаної технології є те, що потік повинен постійно перевіряти в циклі, чи не зняли блокування. Таку ситуацію називають активним очікуванням (busy waiting), а таке блокування — спін-блокуванням (spinlock). Використання циклу під час активного очікування завантажує процесор і допустиме тільки упродовж короткого часу.
Альтернативою активному очікуванню є операція призупинення потоку (thread blocking, sleep). При цьому потік за умови блокування негайно або через якийсь час переходить зі стану виконання у стан очікування, передаючи процесор іншому потокові. Для того щоб реалізувати критичну секцію за допомогою цієї операції, потрібно доповнити її операцією виведення потоку зі стану очікування (поновленням потоку,wakeup).
Призупинення й поновлення потоку спричиняють перемикання контексту, що є досить тривалою операцією. На практиці ці примітиви часто поєднують зі спін-блокуванням, для чого приблизно оцінюють час, необхідний для перемикання контексту, і перед тим, як призупинити потік, виконують спін-блокування впродовж цього часу.
У результаті в найкращому разі вхід у критичну секцію займе набагато менше часу, ніж було б витрачено на перемикання контексту, у гіршому - буде затрачено часу всього удвічі більше, ніж під час негайного призупинення потоку.
Контрольні питання:
Які основні принципи взаємодії потоків?
Які основні причини взаємодії потоків?
В чому полягає проблема змагання?
В чому суть критичної секції?
Які властивості критичної секції?
Блокування.
Як організована програмно-апаратна реалізація блокувань?
Література: Шеховцов В.А. Операційні системи. – К.: Видавнича група BHV, 2005. – 576 с.: іл., стор. 110-117.