
- •8 Взаимодействие процессов 79
- •9 Синхронизация процессов 87
- •10 Тупиковые ситуации 101
- •11 Управление памятью 114
- •12 Управление виртуальной памятью 132
- •13 Интерфейс файловой системы 138
- •14 Некоторые аспекты Реализации файловой системы 156
- •Литература 166 введение
- •Понятие операционной системы
- •Контрольные вопросы
- •Организация компьютерной системы
- •Архитектура компьютера с общей шиной
- •Структура памяти
- •Структура ввода-вывода
- •Контрольные вопросы
- •Классификация Операционных Систем
- •Поддержка многопользовательского режима.
- •Поддержка многопоточности
- •Многопроцессорная обработка
- •Особенности областей использования
- •Контрольные вопросы
- •Функциональные компоненты операционной системы
- •Управление процессами
- •Управление памятью
- •Управление файлами и внешними устройствами
- •Безопасность и защита данных
- •Интерфейс прикладного программирования
- •Пользовательский интерфейс
- •Контрольные вопросы
- •Структура операционной системы
- •Монолитные системы
- •Многоуровневые системы
- •Виртуальные машины
- •Экзоядро
- •Модель клиент-сервер
- •Контрольные вопросы
- •Процессы и потоки
- •Концепция процесса
- •Состояния процесса
- •Реализация процессов
- •Операции над процессами
- •1Создание процессов
- •2Завершение процессов
- •Контрольные вопросы
- •Планирование процессора
- •Планирование процессов. Очереди
- •Планировщики
- •Моменты перепланировки. Вытеснение
- •Переключение контекста
- •Диспетчеризация
- •Критерии планирования процессора
- •Стратегии планирования процессора
- •3Планирование в порядке поступления
- •Пример.
- •4Стратегия sjf
- •5Приоритетное планирование
- •6Карусельная стратегия планирования
- •7Очереди с обратной связью
- •8Гарантированное планирование
- •9Лотерейное планирование
- •10Планирование в системах реального времени
- •Планирование потоков
- •Оценка алгоритмов планирования
- •11Детерминированное моделирование
- •12Моделирование очередей
- •13Имитация
- •Контрольные вопросы
- •Взаимодействие процессов
- •Разделяемая память. Проблема производителя и потребителя
- •Взаимодействие путем передачи сообщений
- •14Буферизация
- •15Исключительные ситуации
- •Потерянные сообщения
- •Вызов удаленных процедур (rpc)
- •Контрольные вопросы
- •Синхронизация процессов
- •Взаимное исключение и критические участки
- •Синхронизация с помощью элементарных приемов нижнего уровня
- •16Запрещение прерываний
- •17Переменные блокировки
- •18Операция проверки и установки
- •Семафоры
- •19Использование семафоров
- •20Реализация семафоров
- •21Тупики и зависания
- •Классические проблемы синхронизации
- •22Проблема ограниченного буфера
- •23Проблема читателей и писателей
- •24Задача об обедающих философах
- •Двоичные семафоры
- •Сигналы
- •Контрольные вопросы
- •Тупиковые ситуации
- •Необходимые условия возникновения тупиков
- •Граф выделения и закрепления ресурсов
- •Методы решения проблемы тупиков
- •25Предотвращение тупиков
- •Взаимное исключение
- •Захват и ожидание
- •Отсутствие перераспределения
- •Условие кругового ожидания
- •26Обход тупиков
- •27Простейший алгоритм обхода тупика
- •28Алгоритм банкира
- •29Обнаружение тупиков
- •30Восстановление после тупика
- •Контрольные вопросы
- •Управление памятью
- •Функции операционной системы по управлению памятью
- •Типы адресов
- •Физическое и логическое адресное пространство
- •Связывание адресов
- •Динамическая загрузка
- •Динамическое связывание
- •Перекрытие программ в памяти
- •Свопинг
- •Смежное размещение процессов
- •31Простое непрерывное распределение
- •32Распределение с несколькими непрерывными разделами
- •Фрагментация
- •Страничная организация памяти
- •Сегментная организация памяти
- •Защита и совместное использование
- •Фрагментация
- •Сегментация в сочетании со страничной памятью
- •Контрольные вопросы
- •Управление виртуальной памятью
- •Подкачка страниц
- •Алгоритмы вытеснения страниц
- •33Случайный выбор (Random)
- •34«Первым пришел первым ушел» (fifo)
- •35Вытеснение по давности использования (lru)
- •36Вытеснение редко используемых страниц (lfu)
- •37Оптимальный алгоритм (opt)
- •Аномалии в алгоритмах страничной реализации
- •38«Толкотня» в памяти
- •39Аномалия Биледи
- •Эффективность и применимость виртуальной памяти
- •Пример.
- •Контрольные вопросы
- •Интерфейс файловой системы
- •Понятие файла. Атрибуты файла и операции с файлами
- •Операции над файлами
- •Типы файлов
- •Структура файлов
- •Методы доступа
- •40Последовательный метод доступа
- •41 Прямой метод доступа
- •42Другие методы доступа
- •Каталоги
- •Логическая структура каталога
- •43Одноуровневая структура каталога
- •44Двухуровневая структура каталога
- •45 Древовидная структура каталога
- •46Организация каталога в виде графа без циклов
- •47Организация каталога в виде произвольного (простого) графа
- •Проблемы защиты файлов
- •48Типы доступа
- •49Списки прав доступа
- •50Другие подходы к защите
- •Контрольные вопросы
- •Некоторые аспекты Реализации файловой системы
- •Общая структура файловой системы
- •Методы выделения дискового пространства
- •51Выделение непрерывной последовательностью блоков
- •52Связный список
- •53Таблица отображения файлов
- •54Индексные узлы
- •Управление свободным и занятым дисковым пространством
- •55Учет при помощи организации битового вектора
- •56Учет при помощи организации связного списка
- •57Размер блока
- •58Структура файловой системы на диске
- •Контрольные вопросы Литература
Операции над процессами
В большинстве систем, допускающих параллельное выполнение процессов, последние могут создаваться и удаляться динамически. Следовательно, такие системы должны иметь механизмы создания и завершения процессов. Рассмотрим, каким образом эти операции выполняются в ОС UNIX и Windows.
1Создание процессов
Процесс может создать несколько новых процессов с помощью соответствующего системного вызова в течение своего выполнения. Порождающий процесс называется родительским (parent process) или процессом-отцом, а новый порожденный родительским – процессом-потомком (children process) или процессом-сыном, дочерним по отношению к порождающим. Каждый из новых процессов может породить другие процессы, формируя дерево процессов (см. рис. 6.2).
Большинство операционных систем (включая семейства UNIX и Windows) присваивают каждому процессу уникальный идентификатор, как правило, целое положительное число.
Если некоторый процесс порождает новый, то существуют две возможности для продолжения работы:
процесс-отец продолжает выполняться вместе со своими сыновьями;
процесс-отец ожидает завершения работы одного или нескольких своих потомков.
Кроме того, возможны два варианта использования адресного пространства порожденным процессом:
процесс-сын является клоном родительского процесса;
процесс-сын создается для исполнения новой программы.
Рисунок 6.10 – Дерево процессов в UNIX-системах
Порождение процессов в системе UNIX происходит в результате выполнения системного вызова fork. ОС строит образ порожденного процесса, являющийся точной копией образа породившего процесса, то есть дублируются дескриптор, контекст и образ процесса. Вновь созданному процессу ОС присваивает целочисленный идентификатор, уникальный на весь период функционирования системы.
После выполнения системного вызова fork() оба процесса продолжают выполнение с одной и той же точки. Чтобы процесс мог опознать, является он родительским процессом или процессом-потомком, системный вызов fork() возвращает в качестве своего значения в породивший процесс идентификатор порожденного процесса, а в порожденный процесс – 0.
Обычно, после развилки одним из процессов выполняется системный вызов exec(), чтобы заменить пространство памяти процесса с новой программой. Этот системный вызов загружает двоичный файл в память (уничтожая образ программы, содержащей exec() обращение к операционной системе) и начинает его выполнение. Таким образом, два процесса способны взаимодействовать, а затем выполняться по разным программам. Родитель может затем породить других потомков; или, если у него нет других задач, подождать завершения потомка путем обращения к системному вызову wait() (см. рис. 6.3).
Рисунок 6.11 – Схема порождения нового процесса в UNIX
Ниже приводится программа, иллюстрирующая описанный подход.
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
pid t pid;
/* развилка */
if ((pid = fork())< 0)
{/* обнаружена ошибка */
fprintf(stderr, “Fork failed\n”);
exit (-1) ;
}
else if (pid == 0)
{/* дочерний процесс*/
execlp ("/bin/ls", "ls", HULL) ;
}
else
{/* родительский процесс */
wait !MULL) ;
printf("Child Complete\n");
exit (0);
}
}
Таким образом, в UNIX порождение нового процесса происходит в два этапа – сначала создается копия процесса-родителя, затем у нового процесса производится замена кодового сегмента на заданный.
В качестве альтернативы рассмотрим создание процесса в Windows. Для создания процесса в Win32 API используется функция CreateProcess(), которая подобна функции fork() в том, что родитель создает новый процесс. Однако, тогда как при использовании fork() порожденный процесс наследует адресное пространство родителя, использование CreateProcess() приводит к загрузке указанной программы в адресное пространство порожденного процесса при его создании. К тому же, системный вызов fork() не требует задания параметров, а для функции CreateProcess() их требуется не менее 10.
Программа на языке C, приведенная ниже иллюстрирует работу функции CreateProcess(), которая создает новый процесс для приложения mspaint.exe. Для большинства параметров, передаваемых в CreateProcess() выберем значения по умолчанию.
#include <stdio.h>
#include <windows.h>
int main (void)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
// выделение памяти
zeromemory(&si, sizeof (si));
si.cb = sizeof (si);
zeromemory(&pi, sizeof (pi));
// создание дочернего процесса
if (!CreateProcess( NULL, // команднаю строка во 2 параметре
'C:\\WINDOWS\\system32\\mspaint.exe', // команда
NULL, // атрибуты защиты процесса по умолчанию
NULL, // атрибуты защиты главного потока по умолчанию
FALSE, // идентификаторы не наследуются
0, // флаги создания не используются
NULL, // наследовать окружение родителя
NULL, // наследовать текущий каталог
&si,
&pi
)
)
{
fprintf(stderr,”Create Process failed\n”);
return -1;
}
// Родительский процесс ожидает окончания дочернего
WaitForSingleObject(pi.hProcess, INFINITE);
printf(”Child complete\n”);
// закрытие объектов
CloseHandle(pi.hProcess,INFINITE);
CloseHandle(pi.hThread);
}