- •Системне програмування, характерні особливості.
- •Асемблер. Варіанти спільного використання асемблера і мов високого рівня.
- •Інструментальні засоби розробки програм на мові Асемблер.
- •Регістри.
- •Користувацькі регістри.
- •Сегментні регістри.
- •Організація роботи з пам’ятю.
- •Сегментна модель пам’яті.
- •Набір команд мікропроцесора.
- •Специфікація типів даних
- •11. Використання арі-функцій.
- •12. Структура програми, приклад простої програми для Windows.
- •13. Передача параметрів через стек
- •14. Використання ресурсів при роботі з діалоговими вікнами.
- •15.Використання ресурсів при роботі з меню.
- •16. Використання акселераторів у файлах ресурсу.
- •17. Ресурси. Переваги використання ресурсів у програмах.
- •18. Використання ресурсів при роботі з іконками, рядками, курсорами.
- •21. Потоки, взаємодія потоків.
- •22. Семафори блять! Події нахуй!
- •23. Критичні секції.
21. Потоки, взаємодія потоків.
Потік може бути створений за допомогою функцій CreateThread. Розглянемо параметри цієї функції.
Й параметр. Покажчик на структуру атрибутів доступу. Має значення тільки для Windows NT. Зазвичай покладається NULL.
Й параметр. Розмір стека потоку. Якщо параметр дорівнює нулю, то береться розмір стека за замовчуванням, що дорівнює розміру стека батьківського потоку.
Й параметр. Покажчик на потокових функцію, з виклику якої починається виконання потоку.
й параметр. Параметр для потокової функції.
й параметр. Прапор, який визначає стан потоку. Якщо прапор дорівнює 0, то виконання потоку починається негайно. Якщо значення прапора потоку CREATESUSPENDED — (4Н), то потік знаходиться в стан очікування і запускається при виконання функції ResumeThread. .
й параметр. Покажчик на змінну, куди буде поміщений дескриптор потоку.
Як вже було сказано, виконання потоку починається з потокової функції. Закінчення роботи цієї функції призводить до природного закінчення роботи потоку. Потік також може закінчити свою роботу, виконавши функцію ExitThread із зазначенням коду виходу.
Поговоримо тепер про багато потокові програми. В принципі, якщо не передбачається, що потоки якось взаємодіють один з одним, технічно не має значення, запущений один або декілька потоків. Складності виникають, коли робота одного потоку залежить від діяльності другого потоку. Тут можливі різні ситуації.
Часто трапляється, що дані неможливо отримувати періодично. Вони можуть, наприклад, залежатиме від діяльності третього процесу. Як же другий процес дізнається, що дані вже готові для передачі? На перший погляд проблема вирішується введенням додаткової змінної, назвемо її Flag. Приймемо, що при Flag = 0 дані не готові, а при Flag — 1 дані готові. Далі діє дуже проста схема.
NO_DAT:
CMP FLAG, 1 JNE NO_DAT ... ; передача даних
MOV FLAG, 0
Це фрагмент, як Ви розумієте, для другого потоку. Перший же потік також повинен перевіряти змінну Flag і, якщо Flag = 0, помістити нові дані та встановити значення змінної Flag, рівне одиниці. Дана схема є зручною, наприклад, коли один процес чекає закінчення роботи іншого процесу.
А що буде, якщо процес передачі даних повинен здійснюватися багаторазово. Легко передбачити, що дана схема буде працювати і в більш складному випадку. Важливо, щоб другий процес міняв вміст Flag тільки після того, як він візьме дані, а перший процес - після того, як звільнить дані. Якщо порушити це правило, то може виникнути колізія, коли, наприклад, другий процес ще не взяв дані, а вони вже змінилися.
Такий підхід можна здійснити і в більш загальному випадку, коли два потоку (або - два процеси) повинні почергово одержувати доступ до одного ресурсу. Даний підхід припускає, що ресурс відкритий або для одного, або для іншого процесу. Якщо б поставити задачу трохи іншим чином - процес або відкрито, або закритий для доступу, то виникло б деяке ускладнення. Дійсно, імовірна така ситуація, коли обидва потоку очікують відкриття ресурсу. Іншими словами, вони безперервно здійснюють перевірку змінної Flag (CMP FLAG, 1). Може статися, що вони обидва майже одночасно звернуться до ресурсу. Цілком зрозуміло, що тут виникає необхідність в "третій силі", яка б займалася розподілом доступу до ресурсу. Наприклад, посилала б повідомлення спочатку одному потоку і, якщо він очікує доступу, давала доступ саме йому, а потім подібний процес повторюється з другим потоком.
Схема, описана вище, дуже зручна, але за умови почергового звернення до ресурсу. Якщо це в загальному випадку не виконується, то даний підхід може дати серйозний збій. Всі наведені тут міркування мають одну мету - показати, що проблема взаємодії потоків і процесів, їх синхронізації, є і складною, і актуальною для багатозадачних ОС.
