
- •Операційні системи Конспект лекцій
- •1. Введення
- •1.1. Предмет і завдання курсу
- •1.2. Рекомендації по літературі
- •1.3. Короткий нарис історії ос
- •1.3.1. Передісторія ос
- •1.3.2. Пакетні ос
- •1.3.3. Ос з поділом часу
- •1.3.4. Однозадачні ос для пеом
- •1.3.5. Багатозадачні ос для пк з графічним інтерфейсом
- •1.4. Класифікація ос
- •1.5. Критерії оцінки ос
- •1.5.2. Ефективність
- •1.5.3. Зручність
- •1.5.4. Масштабованість
- •1.5.5. Здатність до розвитку
- •1.6. Основні функції і структура ос
- •1.7. Ос, що використовуються в подальшому викладі
- •1.7.2. Windows
- •1.7.3. Unix
- •2. Управління пристроями
- •2.1. Основні завдання управління пристроями
- •2.2. Класифікація периферійних пристроїв і їх архітектура
- •2.3. Переривання
- •2.4. Архітектура підсистеми вводу / виводу
- •2.5. Способи організації введення / виводу
- •2.5.1. Введення / висновок з опитування і по перериваннях
- •2.5.2. Активне і пасивне очікування
- •2.5.3. Синхронний і асинхронний ввід / вивід
- •2.6. Буферизація і кешування
- •2.6.1. Поняття буферизації
- •2.6.2. Згладжування нерівномірності швидкостей процесів
- •2.6.3. Розпаралелювання введення та обробки
- •2.6.4. Узгодження розмірів логічної та фізичної записи
- •2.6.5. Редагування при інтерактивному введенні
- •2.6.6. Кешування дисків
- •2.6.7. Випереджаюче читання.
- •2.7. Драйвери пристроїв
- •2.8. Управління пристроями в ms-dos
- •2.8.1. Рівні доступу до пристроїв
- •2.8.2. Драйвери пристроїв в ms-dos
- •2.8.3. Управління символьними пристроями
- •2.8.4. Управління блоковими пристроями
- •2.8.4.1. Структура диска
- •2.8.4.2. Розділи і логічні томи
- •2.8.4.3. Засоби доступу до дисків
- •2.9. Управління пристроями в Windows
- •2.9.1.1. Драйвери пристроїв в Windows
- •2.9.1.2. Доступ до пристроїв
- •2.10. Управління пристроями в unix
- •2.10.1. Драйвери пристроїв в unix
- •2.10.2. Пристрій як спеціальний файл
- •3. Управління даними
- •3.1. Основні завдання управління даними
- •3.2. Характеристики файлів та архітектура файлових систем
- •3.3. Розміщення файлів
- •3.4. Захист даних
- •3.5. Поділ файлів між процесами
- •3.6. Файлова система fat і управління даними в ms-dos
- •3.6.1. Загальна характеристика системи fat
- •3.6.2. Структури даних на диску
- •Структура записи каталога файловой системы fat
- •3.6.4. Робота з файлами в ms-dos
- •3.6.4.1. Системні функції
- •3.6.4.2. Доступ до даних
- •3.6.4.3. Структури даних у пам'яті
- •3.6.5. Нові версії системи fat
- •3.7. Файлові системи і управління даними в unix
- •3.7.1. Архітектура файлової системи unix
- •3.7.1.1. Жорсткі і символічні зв'язку
- •3.7.1.2. Монтовані томи
- •3.7.1.3. Типи і атрибути файлів
- •3.7.1.4. Управління доступом
- •3.7.2. Структури даних файлової системи unix
- •3.7.3. Доступ до даних в unix
- •3.7.4. Розвиток файлових систем unix
- •3.8. Файлова система ntfs і управління даними в Windows
- •3.8.1. Особливості файлової системи ntfs
- •3.8.2. Структури дискових даних
- •3.8.2.1. Головна таблиця файлів
- •3.8.2.2. Атрибути файлу
- •3.8.3. Доступ до даних
- •3.8.4. Захист даних
- •3.8.4.1. Аутентифікація користувача
- •3.8.4.2. Дескриптор захисту
- •4. Управління процесами
- •4.1. Основні завдання управління процесами
- •4.2. Реалізація багатозадачного режиму
- •4.2.1. Поняття процесу і ресурсу
- •4.2.2. Квазіпараллельний виконання процесів
- •4.2.3. Стану процесу
- •4.2.4. Невитісняючаі витісняюча багатозадачність
- •4.2.5. Дескриптор і контекст процесу
- •4.2.6. Реєнтерабельним системних функцій
- •4.2.7. Дисципліни диспетчеризації та пріоритети процесів
- •4.3. Проблеми взаємодії процесів
- •4.3.1. Ізоляція процесів та їх взаємодія
- •4.3.2. Проблема взаємного виключення процесів
- •4.3.3. Двійкові семафори Дейкстри
- •4.3.4. Засоби взаємодії процесів
- •4.3.4.1. Цілочисельні семафори
- •4.3.4.2. Семафори з множинним очікуванням
- •4.3.4.3. Сигнали
- •4.3.4.4. Повідомлення
- •4.3.4.5. Спільна пам'ять
- •4.3.4.6. Програмні канали
- •4.3.5. Проблема тупиків
- •4.4. Управління процесами в ms-dos
- •4.4.1. Процеси в ms-dos
- •4.4.2. Середа програми
- •4.4.3. Запуск програми
- •4.4.4. Завершення роботи програми
- •4.4.5. Перехоплення переривань і резидентні програми
- •4.5. Управління процесами в Windows
- •4.5.1. Поняття об'єкта у Windows
- •4.5.2. Процеси і нитки
- •4.5.3. Планувальник Windows
- •4.5.4. Процес і нитка як об'єкти
- •4.5.5. Синхронізація ниток
- •4.5.5.1. Способи синхронізації
- •4.5.5.2. Об'єкти синхронізації та функції очікування
- •4.5.5.3. Типи об'єктів синхронізації
- •4.5.5.4. Критичні секції
- •4.5.6. Повідомлення
- •4.6. Управління процесами в unix
- •4.6.1. Життєвий цикл процесу
- •4.6.2. Групи процесів
- •4.6.3. Програмні канали
- •4.6.4. Сигнали
- •4.6.5. Засоби взаємодії процесів в стандарті posix
- •4.6.6. Планування процесів
- •4.6.6.1. Стану процесів в unix
- •4.6.6.2. Пріоритети процесів
- •4.6.7. Інтерпретатор команд shell
- •5. Управління пам'яттю
- •5.1. Основні завдання управління пам'яттю
- •5.2. Віртуальні й фізичні адреси
- •5.3.1. Настроювання адрес
- •5.3.2. Розподіл з фіксованими розділами
- •5.3.3. Розподіл з динамічними розділами
- •5.4. Сегментна організація пам'яті
- •5.5. Сторінкова організація пам'яті
- •5.6. Порівняння сегментної і сторінкової організації
- •5.7. Управління пам'яттю в ms-dos
- •5.8. Управління пам'яттю в Windows
- •5.8.1. Структура адресного простору
- •5.8.3. Відображення виконуваних файлів
- •5.8.4. Файли, відображувані на пам'ять
- •5.8.5. Стеки і купи
- •5.9. Управління пам'яттю в unix
- •Література
5.8.5. Стеки і купи
Описані вище засоби керування пам'яттю, засновані на виділенні регіонів, являють собою могутній і красивий інструмент для роботи з великими масивами пам'яті. Однак у практиці програмування частіше зустрічаються прозові завдання, пов'язані з використанням невеликих ділянок пам'яті: виклик функцій з передачею їм параметрів і виділенням локальних змінних, створення та звільнення змінних в динамічній пам'яті і т.п. Але зате ці дрібні операції можуть виконуватися дуже багато разів. Використовувати виділення окремого регіону заради того, щоб отримати 10 - 20 байт пам'яті, це приблизно те ж саме, що застосовувати ракетну зброю в боротьбі з тарганами. Нагадаємо, що мінімальний розмір регіону дорівнює 4 Кб.
Програмісти звикли, що для розміщення параметрів і локальних змінних функцій використовується стек, а виділення ділянок динамічної пам'яті відбувається з «купи» - спеціально призначеній для цього області пам'яті, керованої виконуючою системою мови програмування. Обидва цих механізму отримують підтримку з боку Windows.
При створенні нової нитки вона отримує свій власний стек, розмір якого, якщо він не вказаний явно, приймається рівним 1 Мб. Ця величина може здатися явно надлишкової для більшості програм. Чи варто системі так кидатися пам'яттю?
Насправді, виділяється 1 Мб резервованої пам'яті. Реального витрачання ресурсів пам'яті при цьому не відбувається, хіба що від 2 Гб адресного простору процесу відщипують порівняно невеликий шматочок. Розмір «справжньої» пам'яті, закріпленої за стеком в сторінковому файлі, дорівнює спочатку двом сторінкам, розміщеним в самому кінці зарезервованого регіону, як показано на рис. 5-6.
Рис. 1‑25
Стек за своїм звичаєм зростає в напрямку убування адрес, тому, починаючи зростання з самого старшого адреси, він поступово заповнює одну сторінку, а потім переходить до другої, з меншими адресами. Ця сторінка виділяється з атрибутом PAGE_GUARD, який, нагадаємо, означає, що при першому зверненні до сторінки генерується переривання, що оповіщає про це систему. Для Windows це сигнал, що пора передати стеку ще одну сторінку пам'яті про запас, причому ця сторінка знову отримує атрибут PAGE_GUARD, щоб потім оповістити систему, що стек знову виріс. Так може тривати до тих пір, поки пам'ять не буде передана всім сторінкам регіону стека, крім самої молодшої. Ця сторінка завжди залишається зарезервованої і спроба запису на неї розглядається як переповнення стека. Таким чином, молодша сторінка регіону стека служить бар'єром, що не дозволяє стеку вийти за початок регіону.
А чому необхідний такий бар'єр?
Для розміщення динамічних змінних зручно використовувати об'єкт «купа» (heap). Windows надає кожному процесу власну купу, хендл якої можна отримати викликом функції GetProcessHeap. Після цього нитки процесу можуть запитувати блоки пам'яті з купи, викликаючи функцію HeapAlloc. Параметри цієї функції включають в себе хендл купи, розмір запитуваного блоку і деякі прапори. Після закінчення потреби у виділеному блоці він може бути повернений в купу викликом функції HeapFree.
Невелика проблема виникає в зв'язку з тим, що до однієї і тієї ж купі можуть звертатися різні нитки одного процесу. Не виключено їх одночасне звернення до функцій, що працюють з купою. Виникає проблема взаємного виключення, і Windows вирішує її, використовуючи вбудований мьютекс. Це називається сериализацией доступу до купи, тобто послідовним виконанням запитів (від «serial» - послідовний). Для програми користувача цей мьютекс не видно і можна не звертати на нього уваги. Проте в тому випадку, якщо програміст впевнений, що нитки не можуть перешкодити один одному, він може відключити сериализацию, вказавши відповідний прапор або при відкритті купи, або при запиті блоку. Це декілька підвищує продуктивність.
У деяких випадках виявляється вигідно використовувати не одну, а кілька куп для одного і того ж процесу. Можна назвати, принаймні, дві подібних ситуації.
· Якщо з купою працюють дві або більше ниток процесу, то виділення окремої купи для кожної нитки дозволяє обійтися без серіалізациі, підвищивши таким чином продуктивність.
· Якщо програма запитує з купи блоки різного розміру, то неминуче таке знайоме нам явище, як фрагментація пам'яті. В даному випадку вона призведе до зайвого зростанню купи і до уповільнення роботи. Іноді вдається уникнути фрагментації, виділивши окрему купу для кожного використовуваного розміру блоків. Наприклад, з однієї купи будуть запитуватися блоки тільки розміром 105 байт, а з іншого - розміром 72 байта. При виділенні блоків одного розміру фрагментації не виникає.
Windows дозволяє процесу створити будь-яку кількість додаткових куп. Для цього потрібно викликати функцію HeapCreate, передавши їй два числа: початковий розмір фізичної пам'яті, переданої купі при створенні, і максимальний розмір купи, задаючий розмір регіону зарезервованої пам'яті для купи. Якщо максимальний розмір заданий рівним 0, то купа може рости необмежено.
Коли додаткова купа перестає бути потрібна, можна звільнити займану пам'ять, передавши хендл купи функції HeapDestroy.