Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OS(методичка).docx
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
403.88 Кб
Скачать

4.5.5.4. Критичні секції

Ще одним засобом синхронізації потоків служать змінні типу CRITICAL_SECTION. За призначенням вони збігаються з розглянутими вище мьютекс, однак реалізація двійкового семафора в цьому випадку абсолютно інша. Якщо мьютекс - це один з типів об'єктів ядра, то критичні секції - просто змінні. У чому тут принципова різниця? У тому, що об'єкти існують в пам'яті системи, тому прикладна програма не може напряму звернутися до об'єкта, прочитати або записати його значення. Програма може тільки отримати хендл об'єкта, а потім вона доручає системі виконати ту чи іншу дію з об'єктом, на який вказує даний хендл. Таке рішення дозволяє використовувати один об'єкт для зв'язку декількох процесів, зберігаючи при цьому ізоляцію пам'яті процесу від пам'яті системи і інших процесів.

Недолік використання об'єктів ядра в тому, що звернення до них всякий раз вимагає перемикання контексту з користувальницького на системний і назад, а це вимагає часу. Така ціна ізоляції процесів.

Якщо потрібно синхронізувати роботу ниток одного і того ж процесу, то більш «дешевим» рішенням може бути використання змінних CRITICAL_SECTION. Програміст повинен описати змінну цього типу в програмі процесу, при цьому для всіх ниток процесу буде доступний адресу цієї змінної. Перед початком роботи з критичною секцією одна з ниток процесу повинна викликати функцію InitializeCriticalSection, передавши їй адресу змінної. Потім він може використовувати функцію EnterCriticalSection, щоб зайняти двійковий семафор, і функцію LeaveCriticalSection, щоб звільнити його. Як і для мьютекса, один і той же потік може кілька разів зайняти критичну секцію, але потім повинен стільки ж разів звільнити її. Є ще зручна функція TryEnterCriticalSection, яка дозволяє уникнути блокування і займає критичну секцію, тільки якщо та була вільна у момент звернення. Після закінчення необхідності в синхронізації ниток слід викликати функцію DeleteCriticalSection.

Виклик всіх перерахованих функцій виконується системою набагато швидше, ніж виклик функцій, що працюють з хендл об'єктів, оскільки вся робота виконується в пам'яті зухвалого процесу, без перемикання контексту пам'яті. Але зате неможливо використовувати критичні секції для синхронізації ниток різних потоків, для цього потрібні мьютекс.

4.5.6. Повідомлення

Величезну роль в організації роботи прикладних програм і самої системи Windows грають повідомлення (messages). На обробці повідомлень, що посилаються системою, заснована вся робота з графічним інтерфейсом програм. Процеси також можуть обмінюватися повідомленнями з метою синхронізації дій та обміну даними.

Повідомлення являє собою структуру даних, що містить тип повідомлення, адресат повідомлення (конкретне вікно, всі вікна або нитка процесу), час посилки повідомлення, координати курсора (для повідомлень від миші), а також два параметри, зміст яких залежить від типу повідомлення.

Система посилає повідомлення придатків із найрізноманітніших приводів: при натисканні клавіш і кнопок миші, створенні та закритті вікон, зміни розмірів і положення вікна, виборі об'єкта в якомусь списку, виборі команди в меню і т.п. Часто одне і те ж дія користувача (наприклад, клацання лівою кнопкою миші на пункті меню) викликає посилку декількох різних повідомлень.

Велика частина посилаються повідомлень може оброблятися самою системою за замовчуванням. Прикладна програма може взяти обробку деяких повідомлень на себе, щоб забезпечити необхідну логікою роботи реакцію на певні події (наприклад, при зміні розмірів вікна перерозподілити його площа між окремими панелями; при спробі закрити вікно запросити підтвердження і т.п.). Програма повинна також обробляти повідомлення про посиланих їй командах (при використанні меню, кнопок і т.п.) і повідомлення про необхідність перемалювати вміст вікна.

При створенні будь-якого нового вікна Windows вимагає задати віконну функцію, яка повинна обробляти повідомлення, спрямовані цьому вікну. Нитка, що отримала повідомлення, або викликає віконну функцію одного зі своїх вікон (для вибору вікна використовується функція DispatchMessage), або обробляє повідомлення сама (якщо воно не пов'язане з конкретним вікном).

Є два принципово різних способу посилки повідомлення. Посилаючи повідомлення синхронно, відправник чекає закінчення його обробки, перш ніж продовжити роботу. Асинхронна посилка нагадує опускання листи в поштову скриньку, вона не робить впливу на подальшу роботу відправника. Прикладна програма може посилати будь-які повідомлення синхронним або асинхронним способом, як вважатиме за потрібне розробник. Для цього можуть використовуватися, відповідно, функція SendMessage (синхронна посилка) або функція PostMessage (асинхронна посилка).

Нитка процесу отримує повідомлення, адресовані належним їй вікнам або самої нитки. Для вибірки повідомлень з черги використовується функція GetMessage. У разі відсутності повідомлень нитка блокується до їх надходження. При бажанні програміст може використовувати функцію PeekMessage, яка перевіряє наявність повідомлення, не блокуючи зухвалу нитку.

Реалізація асинхронного способу посилки досить проста: система просто поміщає повідомлення в чергу нитки-одержувача. Синхронна посилка в ранніх, невитисняючих версіях Windows також реалізувалася дуже просто: як безпосередній виклик віконної функції вікна-одержувача, минаючи всякі черзі. Після закінчення обробки керування поверталося відправнику. У сучасних версіях Windows все так і відбувається, якщо нитка посилає повідомлення своєму власному вікна. В інших випадках таке рішення неможливо. По-перше, якщо повідомлення пересилається між нитками різних процесів, то ізоляція процесів в пам'яті не дає можливості однієї нитки викликати іншу як підпрограму. По-друге, навіть для ниток одного процесу такий виклик міг би привести до непередбачуваних наслідків у разі перемикання ниток по кванту часу.

В результаті цього системі доводиться діяти дуже акуратно. Нитка, що послала синхронне повідомлення вікну інший нитки, блокується. Повідомлення поміщається в окрему чергу синхронних повідомлень до нитки-одержувачу. Ця нитка продовжує свою нормальну роботу до моменту, коли вона звернеться за черговим повідомленням, тобто викличе GetMessage або PeekMessage. Тоді система викликає віконні функції нитки для обробки кожного з чекаючих синхронних повідомлень. Тільки коли всі вони оброблені, виконується викликана функція GetMessage або PeekMessage, що перевіряє наявність асинхронних повідомлень в черзі.

В процесі обробки синхронного повідомлення віконна функція не повинна викликати функції, які можуть викликати переключення системи на виконання іншої нитки.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]