ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 24.12.2021
Просмотров: 12199
Скачиваний: 10

Примеры операционных систем
5 0 3
Заголовок
таблицы
MFT
Стандартная Имя Имя для
информация файла MS-DOS Защита Данные
Элемент таблицы MFT для одного файла
Главная
файловая
таблица (MFT)
Рис. 6.28. Главная файловая таблица в системе Windows NT
Поле стандартой информации содержит информацию об отметках времени,
необходимых стандартах POSIX, о числе связей, о битах «только для чтения» и
битах архивирования и т. д. Это поле имеет фиксированную длину и является обя-
зательным. Имя файла может иметь любую длину до 255 символов Unicode. Что-
бы такие файлы стали доступны для старых 16-битных программ, они могут снаб-
жаться дополнительным именем MS-DOS, состоящим максимум из 8 символов,
за которыми следует точка и расширение из 3 символов. Если действительное имя
файла соответствует правилу наименования в MS-DOS (8+3), то второе имя для
MS-DOS не используется.
Далее следует информация о защите. Во всех версиях, вплоть до NT 4.0, в поле
защиты содержался дескриптор защиты. Начиная с NT 5.0, вся информация о за-
щите помещается в один файл, а поле защиты просто указывает на соответствую-
щую часть этого файла.
Для файлов небольшого размера сами данные этих файлов содержатся в эле-
менте главной файловой таблицы, что упрощает их вызов, — для этого не требует-
ся обращаться к диску. Данная идея получила название
непосредственный файл
(immediate file) [100]. Для файлов большого размера это поле содержит указатели
на кластеры, в которых содержатся данные или (что более распространено) блоки
последовательных кластеров, так что номер кластера и его длина могут представ-
лять произвольное количество данных. Если элемент главной файловой таблицы
недостаточно велик для хранения нужной информации, к нему можно привязать
один или несколько дополнительных элементов.
Максимальный размер файла составляет 2
м
байтов. Поясним, что собой пред-
ставляет файл на
2
Ы
байтов. Представим, что файл был написан в двоичной систе-
ме, а каждый 0 или 1 занимает 1 мм пространства. Длина листинга на 2
67
мм соста-
вила бы 15 световых лет. Этого хватило бы для того, чтобы выйти за пределы
Солнечной системы, достичь Альфа Центавра и вернуться обратно.
Файловая система NTFS имеет много других интересных особенностей, в том
числе возможность компрессии данных и отказоустойчивость с применением атомар-
ных транзакций. Дополнительную информацию об этой системе можно найти в [137].

5 0 4 Глава 6. Уровень операционной системы
Примеры управления процессами
Системы NT и UNIX позволяют разделить работу на несколько процессов, кото-
рые выполняются параллельно и взаимодействуют друг с другом, как в примере
с производителем и потребителем, который мы обсуждали ранее. В этом разделе
мы поговорим о том, как происходит управление процессами в обеих системах.
Обе системы поддерживают параллелизм в пределах одного процесса с использо-
ванием потоков, и об этом мы тоже расскажем.
Управление процессами в системе UNIX
В любой момент процесс в системе UNIX может создать подпроцесс, который яв-
ляется его точной копией. Для этого выполняется системный вызов
fork.
Изна-
чальный процесс называется
порождающим процессом,
а новый —
порожденным
процессом.
Два процесса, полученные в результате выполнения операции
fork,
абсолютно идентичны и даже разделяют одни и те же файловые дескрипторы. Каж-
дый из этих двух процессов выполняет свою работу независимо от другого.
Часто порожденный процесс определенным образом дезориентирует дескрип-
торы файлов, а затем выполняет системный вызов
exec,
который замещает его про-
грамму и данные программой и данными из выполняемого файла, определенного
в качестве параметра к вызову
exec.
Например, если пользователь печатает коман-
ду xyz, то интерпретатор команд (оболочка) выполняет операцию
fork,
создавая
таким образом порожденный процесс. А этот процесс выполняет процедуру
exec,
чтобы запустить программу
xyz.
Эти два процесса работают параллельно, но иногда порождающий процесс дол-
жен по каким-либо причинам ждать, чтобы порожденный процесс завершил свою
работу, и только после этого продолжать выполнение тех или иных действий. В этом
случае порождающий процесс выполняет системный вызов
wait
или
waitpid,
в ре-
зультате чего он временно приостанавливается и ждет, пока порожденный про-
цесс не выполнит системный вызов
exit.
Процессы могут выполнять процедуру
fork
сколь угодно часто, в результате чего
получается целое дерево процессов. Посмотрите на рис. 6.29. Здесь процесс А вы-
полнил процедуру
fork
дважды и породил два новых процесса, В и С. Затем про-
цесс В тоже выполнил процедуру
fork
дважды, а процесс С выполнил ее один раз.
Таким образом, получилось дерево из шести процессов.
Исходный процесс
Процессы, порожденные процессом А
Процессы, порожденные дочерними
процессами процесса А
Рис. 6.29. Дерево процессов в системе UNIX
Процессы в системе UNIX могут взаимодействовать друг с другом через специ-
альную информационную структуру, которая называется
каналом.
Канал пред-

Примеры операционных систем 505
ставляет собой вид буфера, в который один процесс записывает поток данных, а
другой процесс забирает эти данные оттуда. Байты всегда возвращаются из канала
в том порядке, в котором они были записаны. Случайный доступ невозможен.
Каналы не сохраняют границы между отрезками данных, поэтому если один про-
цесс записал в канал 4 отрезка по 128 байтов, а другой процесс считывает данные
по 512 байтов, то этот второй процесс получит все данные сразу без указания на то,
что они были записаны в несколько заходов.
В системах System V и Solaris применяется другой метод взаимодействия про-
цессов. Здесь используются так называемые
очереди сообщений.
Процесс может
создать новую очередь сообщений или открыть уже существующую с помощью
вызова
msgget.
Для отправки сообщений используется вызов
msgsnd,
а для получе-
ния —
msgrecv.
Сообщения, отправленные таким способом, отличаются от данных,
помещаемых в канал. Во-первых, границы сообщений сохраняются, а в канал пе-
редается просто поток данных. Во-вторых, сообщения имеют приоритеты, поэто-
му срочные сообщения идут перед всеми остальными. В-третьих, сообщения ти-
пизированы, и вызов
msgrecv
может определять их тип, если это необходимо.
Два и более процесса могут разделять общую область своих адресных про-
странств. UNIX управляет этой разделенной памятью путем отображения одних и
тех же страниц в виртуальное адресное пространство всех разделенных процессов.
В результате запись в общую область, произведенная одним из процессов, будет
видна всем остальным процессам. Этот механизм обеспечивает очень высокую
пропускную способность между процессами. Системные вызовы, включенные в раз-
деленную память, идут по алфавиту (как
shmat
и
shmop).
Еще одна особенность System V и Solaris — наличие семафоров. Принципы их
работы мы уже описывали, когда говорили о производителе и потребителе.
Системы UNIX могут поддерживать несколько потоков управления в пределах
одного процесса. Эти потоки управления обычно называют просто
потоками.
Они
похожи на процессы, которые делят общее адресное пространство и все объекты,
связанные
с
этим адресным пространством (дескрипторы файлов, переменные
окружения и т. д.). Однако каждый поток имеет свой собственный счетчик команд,
свои собственные регистры и свой собственный стек. Если один из потоков при-
останавливается (например, пока не завершится процесс ввода-вывода), другие
потоки в том же процессе могут продолжать работу. Дна потока в одном процессе,
которые действуют как процесс-производитель и процесс-потребитель, сходны с
двумя однопоточными процессами, которые разделяют сегмент памяти, содержа-
щий буфер, хотя не идентичны им. Во втором случае каждый процесс имеет свои
собственные дескрипторы файлов и т. д., тогда как в первом случае все
эти
элемен-
ты общие.
В каких случаях могут понадобиться потоки?
Рассмотрим
сервер World Wide
Web. Такой сервер может хранить в основной памяти кэш часто используемых
web-страниц. Если нужная страница находится в кэш-памяти, то она выдается не-
медленно. Если нет, то она вызывается с диска. К сожалению, на это требуется
довольно длительное время (обычно 20 млс), и на это время процесс блокируется
и не может обслуживать новые поступающие запросы, даже если эти web-страницы
находятся в кэш-памяти.

5 0 6
Глава 6. Уровень операционной системы
По этой причине было принято решение сделать несколько потоков в одном
процессе, которые разделяют общую кэш-память web-страниц. Если один из пото-
ков блокируется, новые запросы могут обрабатываться другими потоками. Пре-
дотвратить блокировку процессов можно и без использования потоков. Для этого
потребуется иметь несколько процессов, но тогда нужно будет продублировать кэш,
а это несколько расточительно, поскольку размер памяти ограничен.
Стандарт системы UNIX для потоков называется pthreads. Он определяется стан-
дартом POSIX (P1003.1C) и содержит вызовы для управления потоками и их син-
хронизации. Управляется ли потоками ядро, или они полностью находятся в пользо-
вательском пространстве, в стандарте не определено. Наиболее распространенные
вызовы для работы с потоками приведены в табл. 6.13.
Таблица 6.13.
Основные вызовы для потоков, определенные в стандарте POSIX
Вызов потока Значение
pthread_create Создает новый поток в адресном пространстве
вызывающей процедуры
pthread_exit Завершает поток
pthreadjoin Ждет завершения потока
pthread_mutex_init Создает новый мьютекс
pthread_mutex_destroy Удаляет мьютекс
pthread_mutex_lock Блокирует мьютекс
pthread_mutex_unlock Снимает блокировку с мьютекса
pthread_cond_init Создает переменную условия
pthread_cond_destroy Удаляет переменную условия
pthread_cond_wait Ждет переменную условия
pthread_cond_signal Снимает блокировку с одного из потоков, который ждет
переменную условия
Давайте рассмотрим эти вызовы. Первый вызов,
pthread_create,
создает новый
поток. После выполнения этой процедуры в адресном пространстве появляется на
один поток больше. Поток, который выполнил свою работу, вызывает
pthread_exit.
Если потоку нужно подождать, пока другой поток не окончит свою работу, он вы-
зывает
pthreadjoin.
Если этот другой поток уже закончил свою работу, вызов
pthreadjoin
немедленно завершается.
Потоки можно синхронизировать с помощью специальных объектов, которые
называются
мьютексами.
Обычно мьютекс управляет каким-либо ресурсом (на-
пример, буфером, разделенным между двумя потоками). Для того чтобы в конк-
ретный момент времени только один поток мог получать доступ к общему ресур-
су, потоки дожны запирать мьютекс перед использованием ресурса и отпирать его
после завершения работы с ним. Таким образом можно избежать состояния гонок,
поскольку этому протоколу подчиняются все потоки. Мьютексы похожи на би-
нарные семафоры (то есть семафоры, которые могут принимать только два значе-
ния: 0 или 1). Эти объекты получили название «мьютексы» (mutexes), поскольку
они используются для обеспечения взаимного исключения доступа к какому-либо
из ресурсов (MUTual Exclusion по-английски значит «взаимное исключение»).

Примеры операционных систем 507
Мыотексы можно создавать и разрушать с помощью вызовов
pthread jnutexjnit
и
pthread_mutex_destroy
соответственно. Мьютекс может находиться в одном из
двух состояний: блокированном и неблокированном. Если потоку нужно устано-
вить блокировку на незапертый мьютекс, он использует
pthread'_mutex_lock,
а за-
тем продолжает работу. Однако если поток пытается запереть мьютекс, который
уже заперт, он блокируется. Когда поток, который в данный момент использует
общий ресурс, завершит работу с этим ресурсом, он должен разблокировать соот-
ветствующий мьютекс с помощью
pthread_mutex_unlock.
Мыотексы предназначены для кратковременной блокировки (например, для
защиты общей переменной). Они не предназначены для длительной синхрониза-
ции (например, для ожидания, пока освободится накопитель на магнитной ленте).
Для длительной синхронизации существуют
переменные условия (condition
variables).
Эти переменные создаются и удаляются с помощью вызовов
pthread_
cond_init
и
pthread_cond__destroy
соответственно.
Если, например, поток обнаружил, что накопитель на магнитной ленте, кото-
рый ему нужен, в данный момент занят, этот поток совершает
pthread_cond_wait
над переменной условия. Когда поток, который использует накопитель на магнит-
ной ленте, завершает свою работу с этим устройством (а это может произойти через
несколько часов), он посылает сигнал
pthread_cond_signal,
чтобы разблокировать
ровно один поток, который ожидает эту переменную условия. Если ни один поток
не ожидает эту переменную, сигнал пропадает. У переменных условия (condition
variables) нет счетчика, как у семафоров. Отметим, что над потоками, мьютексами
и переменными условия можно выполнять и некоторые другие операции.
Управление процессами в Windows NT
NT поддерживает несколько процессов, которые могут взаимодействовать и син-
хронизироваться. Каждый процесс содержит по крайней мере один поток, кото-
рый, в свою очередь, содержит по крайней мере одну
нить
(fiber) (это легковесный
поток). Процессы, потоки и нити в совокупности обеспечивают набор средств для
поддержания параллелизма и в машинах с одним процессором, и в многопроцес-
сорных системах.
Новые процессы создаются с помощью функции API
CreateProcess.
Эта функ-
ция имеет 10 параметров, каждый из которых имеет множество опций. Ясно, что
такая разработка гораздо сложнее соответствующей схемы в UNIX,
где fork
вооб-
ще не имеет параметров, a
exec
имеет всего три параметра: указатели на имя файла,
который нужно выполнить, на массив параметров командной строки и на строки
описания конфигурации. Ниже изложены 10 параметров функции
CreateProcess:
1. Указатель на имя выполняемого файла.
2. Сама командная строка.
3. Указатель на дескриптор защиты для данного процесса.
4. Указатель на дескриптор защиты для внутреннего потока.
5. Бит, который сообщает, наследует ли новый процесс идентификаторы
(handles) исходного процесса.
6. Различные флаги (например, ошибка, приоритет, отладка, консоль).
7. Указатель на строки описания конфигурации.