- •Конспект по курсу лекций Операционные системы
- •Структура вычислительной системы
- •Аппаратный уровень вычислительной системы
- •Системы программирования
- •Модель организации прерываний с использованием регистра «слово состояние процессора»
- •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Й процесс:
- •Механизм сокетов
- •Типы сокетов.
- •Функция создания сокета
- •Запрос на соединение
- •Прослушивание сокета
- •Подтверждение соединения
- •Прием и передача данных
- •Закрытие сокета
- •Пример. Работа с локальными сокетами
- •Пример работы с сокетами в рамках сети.
Пример. Использование канала.
Процесс посылает данные самому себе. Описан массив из двух целых чисел, который передается в функцию pipe (в системный вызов pipe), pipe его заполнил. Далее, используя нулевой дескриптор, осуществляем чтение из канала, используя первый – запись. Понятно, здесь просто строчка записывается, потом считывается. Затем закрываются оба дескриптора из pipes. Прочитанная строка записывается на стандартный вывод и после этого программа завершается. Пример условный, потому что в рамках одного процесса каналы никто не использует.
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
char *s = ”chanel”;
char buf[80];
int pipes[2];
pipe(pipes);
write(pipes[1], s, strlen(s) + 1);
read(pipes[0], buf, strlen(s) + 1);
close(pipes[0]);
close(pipes[1]);
printf(“%s\n”, buf);
return 0;
}
Как правило каналы используются для взаимодействия между двумя процессами. И тут-то как раз и становится существенным, что это есть средство для родственных процессов. Поскольку канал настолько характеризуется файловыми дескрипторами, то для того, чтобы сделать его доступным для другого процесса, существует один единственный способ – унаследовать дескрипторы при порождении сыновнего процесса. Т.е. должна быть следующая последовательность действий: сначала порождается канал, после чего появляется открытый файловый дескриптор, и затем порождается вся необходимая иерархия на процессы, при этом открытые дескрипторы, естественно, наследуются всеми процессами потомками. Тем самым все процессы потомки, порожденные после того, как этот канал будет создан, и их потомки, если они породят в свою очередь каких-то своих потомков, они имеют доступ к этому каналу, потому что у них есть открытый дескриптор к этому каналу. И больше никакие процессы к нему доступа не имеют и не могут его никак получить, потому что этот дескриптор никак не может быть передан, даже если передать это целое число какому-то другому процессу, то оно для него ничего не будет означать, поскольку у него в таблице файловых дескрипторов отсутствует специальная запись, которая ассоциирована с этим контролем. Именно в этом и заключается смысл фразы, когда говорится о том, что канал – это средство взаимодействия для родственных процессов.
Пример. Схема взаимодействия процессов с использованием канала.
Сначала идет вызов pipe, затем fork(), благодаря которому образуется несколько процессов, и соответственно внутри if (fork()) процесс-отец, он закрывает дескриптор чтения и пользуется только записывающей стороной. В сыне происходит, соответственно, происходит все наоборот, он закрывает дескриптор записи и осуществляет чтение из канала. Как правило, канал используется как однонаправленное средство, т.е. данные будут передвигаться только в одном направлении, в данном случае от отца к сыну: отец записывает данные – сын их читает в том же порядке, в котором их записал отец. Обратите внимание на закрывание дескрипторов. Понятно, что это, в принципе, не нужно, поскольку если программа будет завершена, то все дескрипторы и так закроются. Но в данном случае эта строка имеет очень важный смысл: ранее уже говорилось о том, что при попытке чтения большего числа байт из канала, чем в нем находится, чтение будет заблокировано в том случае, если в канале не находится символ EOF, который туда попадает, когда закрывается последний записывающий дескриптор. Последний записывающий дескриптор будет закрыт тогда, когда его закроет процесс-отец, т.е. он запишет все необходимые данные, после чего закроет дескриптор, и собственно это будет означать, что больше данных не будет. В случае, если сын не закроет свой унаследованный дескриптор записи, то после того, как отец закроет свой дескриптор записи останется еще один записывающий дескриптор к тому же каналу в процессе сыне. Хоть он его и не использует (но системе-то это неизвестно), в последнем чтении процесс-сын зациклится, т.к. символ EOF в канал не попадает (поскольку в момент закрытия записывающей стороны это не последний записывающий дескриптор). Поэтому ненужные дескрипторы записи в канал важно обязательно закрывать, потому что иначе последнее чтение из канала будет заблокировано навечно.
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int fd[2];
pipe(fd);
if (fork())
{/*процесс-родитель*/
close(fd[0]); /* закрываем ненужный дескриптор */
write (fd[1], …);
…
close(fd[1]);
…
}
else
{/*процесс-потомок*/
close(fd[1]); /* закрываем ненужный дескриптор */
while(read (fd[0], …))
{
…
}
…
}
}
