- •Конспект по курсу лекций Операционные системы
- •Структура вычислительной системы
- •Аппаратный уровень вычислительной системы
- •Системы программирования
- •Модель организации прерываний с использованием регистра «слово состояние процессора»
- •3.6.1.1 Устройство последовательного доступа
- •Организация управления внешними устройствами
- •Иерархия памяти
- •Аппаратная поддержка ос и систем программирования
- •Некоторые проблемы
- •1. Вложенные обращения к подпрограммам
- •2. Накладные расходы при смене обрабатываемой программы:
- •4. Фрагментация памяти
- •4.2.1 Регистровые окна ( register window )
- •Системный стек
- •Виртуальная память.
- •Базирование адресов.
- •Страничная память.
- •Многомашинные, многопроцессорные ассоциации.
- •Терминальные комплексы
- •Компьютерные сети.
- •Семейство протоколов tcp/ip
- •Ip адрес представляется последовательностью четырех байтов. В адресе кодируется уникальный номер сети, а также номер компьютера (сетевого устройства в сети).
- •Транспортный уровень
- •Уровень прикладных программ
- •Сетевые, распределенные ос
- •Операционные системы Основные понятия
- •Структура ос.
- •Модельная ос
- •Жизненный цикл процесса
- •Типы операционных систем
- •Системы разделения времени
- •Управление внешними устройствами. Архитектура.
- •Программное управление внешними устройствами
- •Буферизация обмена
- •Планирование дисковых обменов
- •Raid системы.
- •Файлы устройств, драйверы
- •Управление оперативной памятью
- •Двухуровневая организация
- •Структурная организация файлов
- •Атрибуты файла
- •Типовые программные интерфейсы работы с файлами
- •Подходы в практической реализации файловой системы Структура «системного» диска
- •Модели реализации файлов Непрерывные файлы
- •Файлы, имеющие организацию связанного списка.
- •Индексные узлы (дескрипторы)
- •Модели организации каталогов
- •Варианты соответствия: имя файла – содержимое файла
- •Координация использования пространства внешней памяти
- •Учет свободных блоков файловой системы Связный список свободных блоков
- •Использование битового массива
- •Организация фс Unix
- •Логическая структура каталогов
- •Внутренняя организация фс Модель версии System V Структура фс
- •Работа с массивами номеров свободных блоков
- •Работа с массивом свободных ид
- •Индексные дескрипторы
- •Адресация блоков файла
- •Файл каталог
- •Установление связей
- •Недостатки фс модели версии System V
- •Модель версии ffs bsd
- •Стратегии размещения
- •Внутренняя организация блоков
- •Структура каталога ffs
- •Понятие «процесс».
- •Процессы в ос Unix Системно-ориентированное определение процесса
- •Базовые средства организации и управления процессами
- •Семейство системных вызовов exec()
- •Использование схемы fork-exec
- •Формирование процессов 0 и 1
- •. Планирование Основные задачи планирования
- •Планирование очереди процессов на начало обработки
- •Кванты постоянной длины.
- •Кванты переменной длины
- •Класс подходов, использующих линейно возрастающий приоритет.
- •Разновидности круговорота.
- •Смешанные алгоритмы планирования
- •Планирование в системах реального времени
- •Общие критерии для сравнения алгоритмов планирования
- •Планирование в ос unix
- •Планирование в Windows nt.
- •Планирование свопинга в ос Unix
- •Взаимодействие процессов: синхронизация, тупики Параллельные процессы
- •Проблемы организации взаимного исключения
- •Тупики (deadlocks)
- •Способы реализации взаимного исключения
- •Семафоры Дейкстры
- •Мониторы
- •Обмен сообщениями
- •Классические задачи синхронизации процессов
- •Задача «читателей и писателей»
- •Задача о «спящем парикмахере»
- •Реализация взаимодействия процессов
- •Сигналы
- •Системный вызов kill()
- •Системный вызов signal()
- •Пример 1.
- •Пример 2.
- •5 Пример. Программа “Будильник”.
- •Пример. Двухпроцессный вариант программы “Будильник”.
- •Пример. Использование канала.
- •Пример. Схема взаимодействия процессов с использованием канала.
- •Пример. Реализация конвейера.
- •Пример. Совместное использование сигналов и каналов – «пинг-понг».
- •Именованные каналы. Особенность именованных каналов в ос Unix.
- •Пример. «Клиент-сервер».
- •Межпроцессное взаимодействие, проводимое по модели «главный-подчинённый».
- •Системный вызов ptrace()
- •Общая схема трассировки процессов
- •Пример. Использование трассировки.
- •Система межпроцессного взаимодействия ipc.
- •Очередь сообщений
- •Системный вызов msgget()
- •Функция msgsnd()
- •Функция msgrcv()
- •Функция msgctl()
- •Пример. Использование очереди сообщений.
- •Пример. Очередь сообщений. Модель «клиент-сервер».
- •Разделяемая память.
- •Пример. Работа с общей памятью в рамках одного процесса.
- •Семафоры
- •Пример. Использование разделяемой памяти и семафоров.
- •1Й процесс:
- •2Й процесс:
- •Механизм сокетов
- •Типы сокетов.
- •Функция создания сокета
- •Запрос на соединение
- •Прослушивание сокета
- •Подтверждение соединения
- •Прием и передача данных
- •Закрытие сокета
- •Пример. Работа с локальными сокетами
- •Пример работы с сокетами в рамках сети.
Базовые средства организации и управления процессами
Второе определение процесса Unix.
Системный вызов – специальная функция, позволяющая процессу обращаться к ядру ОС за выполнением тех или иных действий.
Это может быть запрос на выполнение операций обмена, управления процессами, получения системной информации и т.п. При выполнении системного вызова в процессе происходит инициация специального прерывания «обращение к системе». В разных системах детали реализации системного вызова могут отличаться друг от друга и название прерывания «обращение к системе» здесь выбрано достаточно условно. В любом случае использование системного вызова влечет за собой накладные расходы, связанные со сменой контекста выполняющегося в данный момент процесса.
Если системный вызов не выполняется или выполняется нештатно, то он возвращает –1 в коде ответа и в переменной errno будет находится код причины отказа (для диагностирования результатов выполнения системного вызова в процессе используется переменная errno, объявленная в файле errno.h).
Процесс в ОС Unix – это объект, порожденный системным вызовом fork().
Данный системный вызов является единственным стандартным средством порождения процессов в системе Unix.
Ниже рассмотрим возможности данного системного вызова подробнее.
Создание нового процесса
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
Для порождения новых процессов в UNIX существует единая схема, с помощью которой создаются все процессы, существующие в работающем экземпляре ОС UNIX, за исключением первых двух процессов (0-го и 1-го)
Для создания нового процесса в операционной системе UNIX используется системный вызов fork().
При удачном завершении возвращается:
- сыновьему процессу значение 0
- родительскому процессу PID порожденного процесса
При неудачном завершении возвращается –1, код ошибки устанавливается в переменной errno
В результате вызова fork() в таблицу процессов заносится новая запись, и порожденный процесс получает свой уникальный идентификатор. Для нового процесса создается контекст, большая часть содержимого которого идентична контексту родительского процесса, в частности, тело порожденного процесса содержит копии сегментов кода и данных его родителя.
Сыновний процесс наследует от родительского процесса:
окружение - при формировании процесса ему передается некоторый набор параметров-переменных, используя которые, процесс может взаимодействовать с операционным окружением (интерпретатором команд и т.д.);
файлы, открытые в процессе-отце, за исключением тех, которым было запрещено передаваться процессам-потомкам с помощью задания специального параметра при открытии. (Речь идет о том, что в системе при открытии файла с файлом ассоциируется некоторый атрибут, который определяет правила передачи этого открытого файла сыновним процессам. По умолчанию открытые в «отце» файлы можно передавать «потомкам», но можно изменить значение этого параметра и блокировать передачу открытых в процессе-отце файлов.);
способы обработки сигналов;
разрешение переустановки эффективного идентификатора пользователя;
разделяемые ресурсы процесса-отца;
текущий рабочий каталог и домашний каталоги
и т.д.
Не наследуются от родительского процесса:
- Идентификатор процесса (PID)
- Идентификатор родительского процесса (PPID)
- Сигналы, ждущие доставки в родительский процесс
- Время посылки ожидающего сигнала, установленное системным вызовом alarm()
- Блокировки файлов, установленные родительским процессом
По завершении системного вызова fork() каждый из процессов – родительский и порожденный – получив управление, продолжат выполнение с одной и той же инструкции одной и той же программы, а именно с той точки, где происходит возврат из системного вызова fork(). Вызов fork() в случае удачного завершения возвращает сыновнему процессу значение 0, а родительскому PID порожденного процесса. Это принципиально важно для различения сыновнего и родительского процессов, так как сегменты кода у них идентичны. Таким образом, у программиста имеется возможность разделить путь выполнения инструкций в этих процессах. В случае неудачного завершения, т.е. если сыновний процесс не был порожден, системный вызов fork() возвращает –1, код ошибки устанавливается в переменной errno.
Пример
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
printf("PID=%d; PPID=%d \n",getpid(), getppid());
/*печать PID текущего процесса и PID процесса-предка */
fork();
/*создание нового процесса, с этого момента два процесса функционируют параллельно и независимо*/
printf("PID=%d; PPID=%d \n",getpid(), getppid());
/*оба процесса печатают PID текущего процесса и PID процесса-предка*/
return 0;
}
Напечатается две строки, какая первой – неизвестно. Какой идентификатор родительского процесса распечатает вновь созданный процесс, если процесс-предок завершит свою работу раньше? (см. ответ дальше по тексту)
Пример
Программа создает два процесса – процесс-предок распечатывает заглавные буквы, а процесс-потомок строчные.
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
char ch, first, last;
int pid;
if((pid=fork())>0)
{
/*процесс-предок*/
first =’A’;
last =’Z’;
}
else
{
/*процесс-потомок*/
first =’a’;
last =’z’;
}
for (ch = first; ch <= last; ch++)
{
write(1,&ch,1);
}
return 0;
}
Оба процесса распечатывают буквы одним и тем же оператором for. Оба процесса имеют возможность получить управление, таким образом любой из них может начать исполнение первым.
