Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

1321

.pdf
Скачиваний:
1
Добавлен:
07.01.2021
Размер:
1.06 Mб
Скачать

восстановление потерянных данных на резервном диске;

периодическая замена отказавших дисков на новые. RAID1: Зеркальные диски.

Зеркальные диски представляют традиционный способ

повышения надежности магнитных дисков. Это наиболее дорогостоящий из рассматриваемых способов, так как все диски дублируются и при каждой записи информация записывается также и на проверочный диск. Таким образом, приходится идти на некоторые жертвы в пропускной способности ввода/вывода и емкости памяти ради получения более высокой надежности. Зеркальные диски широко применяются многими фирмами. В частности компания Tandem Computers применяет зеркальные диски, а также дублирует контроллеры и магистрали ввода/вывода с целью повышения отказоустойчивости. Эта версия зеркальных дисков поддерживает параллельное считывание.

RAID 2: матрица с поразрядным расслоением

Один из путей достижения надежности при снижении потерь емкости памяти может быть подсказан организацией основной памяти, в которой для исправления одиночных и обнаружения двойных ошибок используются избыточные контрольные разряды. Такое решение можно повторить путем поразрядного расслоения данных и записи их на диски группы, дополненной достаточным количеством контрольных дисков для обнаружения и исправления одиночных ошибок. Один диск контроля четности позволяет обнаружить одиночную ошибку, но для ее исправления требуется больше дисков.

RAID 3: аппаратное обнаружение ошибок и четность Большинство контрольных дисков, используемых в RAID уровня

2, нужны для определения положения неисправного разряда. Эти диски становятся полностью избыточными, так как большинство контроллеров в состоянии определить, когда диск отказал при помощи специальных сигналов, поддерживаемых дисковым интерфейсом, либо при помощи дополнительного кодирования информации, записанной на диск и используемой для исправления случайных сбоев. По существу, если контроллер может определить положение ошибочного разряда, то для восстановления данных требуется лишь один бит четности. Уменьшение числа контрольных дисков до одного на группу снижает избыточность емкости до вполне разумных размеров. Часто количество дисков в группе равно 5 (4 диска данных плюс 1 контрольный). Подобные устройства выпускаются, например, фирмами Maxtor и Micropolis. Каждое из таких устройств воспринимается машиной как отдельный логический диск с учетверенной пропускной способностью, учетверенной емкостью и

значительно более высокой надежностью. RAID 4: внутригрупповой параллелизм

RAID уровня 4 повышает производительность передачи небольших объемов данных за счет параллелизма, давая возможность выполнять более одного обращения по вводу/выводу к группе в единицу времени. Логические блоки передачи в данном случае не распределяются между отдельными дисками, вместо этого каждый индивидуальный блок попадает на отдельный диск.

Достоинство поразрядного расслоения состоит в простоте вычисления кода Хэмминга, что необходимо для обнаружения и исправления ошибок в системах уровня 2. В RAID уровня 3 обнаружение ошибок диска с точностью до сектора осуществляется дисковым контроллером. Следовательно, если записывать отдельный блок передачи в отдельный сектор, то можно обнаружить ошибки отдельного считывания без доступа к дополнительным дискам. Главное отличие между системами уровня 3 и 4 состоит в том, что в последних расслоение выполняется на уровне сектора, а не на уровне битов или байтов.

RAID 5: четность вращения для распараллеливания записей RAID уровня 4 позволяли добиться параллелизма при считывании

отдельных дисков, но запись по-прежнему ограничена возможностью выполнения одной операции на группу, так как при каждой операции должны выполняться запись и чтение контрольного диска. Система уровня 5 улучшает возможности системы уровня 4 посредством распределения контрольной информации между всеми дисками группы.

Это небольшое изменение оказывает огромное влияние на производительность записи небольших массивов информации. Если операции записи могут быть спланированы так, чтобы обращаться за данными и соответствующими им блоками четности к разным дискам, появляется возможность параллельного выполнения N/2 записей, где N - число дисков в группе. Данная организация имеет одинаково высокую производительность при записи и при считывании как небольших, так и больших объемов информации, что делает ее наиболее привлекательной в случаях смешанных применений.

2.ЛАБОРАТОРНЫЕ РАБОТЫ

2.1Лабораторная работа 1 «Управление программами.

Планирование приоритетов»

Рекомендуемая литература: 1, 5, 6.

Перечень дополнительных ресурсов: 2, 3, 4.

Цель: обучение управлением программами и планированию приоритетов.

Задание:

-выполнить команды по созданию, копированию, перемещению, переименованию и удалению папок и файлов, по определению и по изменению атрибутов файлов и папок;

-исследовать уровень безопасности операционной системы.

2.2 Лабораторная работа 2 «Интерфейс программирования прикладных программ Win32»

Рекомендуемая литература: 5, 6. Перечень дополнительных ресурсов: 4.

Цель: изучить интерфейс вызова функций Win32 API. Освоить на практике использование системных вызовов по созданию и завершению объектов ядра ОС Windows.

Задание: Интерфейс системных вызовов. Если исходить из принципа минимального механизма, тогда операционная система должна предоставлять настолько мало системных вызовов, насколько это возможно (необходимый минимум), и каждый системный вызов должен быть настолько прост, насколько это возможно (но не проще). Объединяющая парадигма данных может играть главную роль в этом. Например, если файлы, процессы, устройства ввода-вывода и прочее будут выглядеть как файлы или объекты, все они могут читаться при помощи всего одного системного вызова read. В противном случае пришлось бы иметь различные системные вызовы, такие как read_file, read_proc, read_tty и т. д.

В некоторых случаях может потребоваться несколько вариантов системных вызовов, но, как правило, на практике лучше иметь один системный вызов, обрабатывающий общий случай, с различными библиотечными процедурами, скрывающими этот факт от программистов. Например, в операционной системе UNIX есть системный вызов exec для замены виртуального адресного пространства процесса. Наиболее общий вариант его использования выглядит следующим образом:

exec(name. argp. envp);

Данный системный вызов загружает исполняемый файл пате и передает ему аргументы, на которые указывает argp, и список переменных окружения, на который указывает envp.

Эти процедуры всего лишь помещают аргументы в массив, после чего обращаются к системному вызову exec, который и выполняет всю работу. Такая схема является лучшей в обоих смыслах: благодаря единственному простому системному вызову операционная система сохраняет свою простоту, в то же самое время программист получает возможность обращаться к системному вызову exec различными способами.

Разумеется, пытаясь использовать один-единственный системный вызов для всех случаев жизни, легко дойти до крайностей. Для создания процесса в операционной системе UNIX требуется два системных вызова: fork, за которым следует exec. У первого вызова нет параметров; у второго вызова три параметра. Для сравнения: у вызова Win32 API для создания процесса, CreateProcess, 10 параметров, один из которых представляет собой указатель на структуру с дополнительными 18 параметрами. Давным-давно следовало задать вопрос: «Произойдет ли катастрофа, если мы опустим что-нибудь из этого?» Правдивый ответ должен был звучать так: «В некоторых случаях программист будет вынужден совершить больше работы для достижения определенного эффекта, зато мы получим более простую, компактную и надежную операционную систему». Конечно, человек, предлагающий версию с этими 10 + 18 параметрами, мог добавить: «Но пользователи любят все эти возможности». Возразить на это можно было бы так: «Еще больше им нравятся системы, которые используют мало памяти и никогда не ломаются». Компромисс, заключающийся в большей функциональности за счет использования большего объема памяти, по крайне мере, виден невооруженным глазом и ему можно дать оценку (так как стоимость памяти известна). Однако трудно оценить количество дополнительных сбоев в год, которые появятся благодаря внедрению новой функции. Кроме того, неизвестно, сделали бы пользователи тот же выбор, если им заранее была известна эта скрытая цена. Этот эффект можно резюмировать первым законом программного обеспечения Таненбаума:

При увеличении размера программы количество содержащихся в ней ошибок также увеличивается.

Когда к программе добавляются новые функции, при этом к ней добавляются новые процедуры, а вместе с ними и новые ошибки. Программисты, полагающие, что при добавлении новых функций к программе не добавится новых ошибок, либо являются новичками в программировании, либо верят, что за ними присматривает добрая фея.

Простота является не единственным принципом, которым следует руководствоваться при разработке системных вызовов.

Если у аппаратного обеспечения есть крайне эффективный способ выполнить что-либо, программистам следует предоставить простой доступ к этой возможности, а не хоронить ее внутри некой абстракции. Назначение абстракций заключается в том, чтобы скрывать нежелательные свойства, а не полезные свойства. Например, предположим, что у аппаратуры есть специальный способ перемещения больших участков изображений по экрану (то есть в видеопамяти) на высокой скорости. В этом случае ввод нового системного вызова, предоставляющего доступ к этому механизму, будет оправдан, так как это лучше, чем читать данные из видеоОЗУ в обычную память, а затем писать эти данные обратно в видеоОЗУ. Новый вызов должен просто перемещать биты в видеопамяти. Если этот новый системный вызов будет быстрым, это позволит пользователям создавать более эффективные программы. Если системный вызов медленный, никто не будет им пользоваться.

При проектировании системы возникает также вопрос использования ориентированных на соединение вызовов или вызовов, не использующих соединений. Стандартные системные вызовы UNIX и Win32 для чтения файлов являются ориентированными на соединение. Сначала вы открываете файл, затем читаете его и, наконец, закрываете файл. Некоторые протоколы работы с удаленными файлами также являются ориентированными на соединение. Например, чтобы использовать протокол FTP, пользователь сначала регистрируется на удаленной машине, читает файлы, а затем выходит из системы.

С другой стороны, некоторые протоколы удаленного доступа к файлам не требуют соединений. Например, протокол NFS не требует соединений, как было показано в главе 10. Каждый вызов NFS является независимым, поэтому файлы не открываются до их чтения или записи, разумеется, файлы не нужно закрывать после чтения или записи. Всемирная паутина также не требует соединений: чтобы прочитать web-страницу, вы просто запрашиваете ее. Не требуется никаких предварительных настроек (TCP-соединение все-таки требуется, но оно представляет собой более низкий уровень протокола; протокол HTTP, используемый для доступа к самой web-странице, не требует соединений).

От того, какой из механизмов выбрать - ориентированный на соединение или не требующий соединений, - зависит, будет ли от механизма требоваться дополнительная работа (например, по открытию файлов), или же эта работа перекладывается на плечи использующей механизм прикладной программы. В последнем случае получается существенный выигрыш в эффективности, если к одному и

тому же файлу программа обращается много раз. Для системы вводавывода на одной машине, где стоимость подготовки ввода-вывода (открытия файла) низка, вероятно, лучше использовать стандартный способ (сначала открыть, затем использовать). Для удаленных файловых систем возможно использование обоих вариантов.

Другой вопрос, возникающий при проектировании интерфейса системных вызовов, заключается в его открытости. Список системных вызовов, определяемых стандартом POSIX, легко найти. Эти системные вызовы поддерживаются всеми системами UNIX, как и небольшое количество других вызовов, но полный список всегда публикуется. Корпорация Microsoft, напротив, никогда не публиковала список системных вызовов Windows 2000. Вместо этого публикуются функции интерфейса Win32 API, а также вызовы других интерфейсов; эти списки содержат огромное количество библиотечных вызовов (более 13 000 в Windows 2000), но только малое их число является настоящими системными вызовами. Аргумент в пользу открытости системных вызовов заключается в том, что программистам становится известна цена использования функций. Функции, исполняемые в пространстве пользователя, выполняются быстрее, чем те, которые требуют переключения в режим ядра. Закрытость системных вызовов также имеет свои преимущества, заключающиеся в том, что в результате достигается гибкость в реализации библиотечных процедур. То есть разработчики операционной системы получают возможность изменять действительные системные вызовы, сохраняя при этом работоспособность прикладных программ.

2.3 Лабораторная работа 3 «Основные особенности и характеристики ОС семейства Linux»

Рекомендуемая литература: 5, 6. Перечень дополнительных ресурсов: 3, 4.

Цель: Освоить на практике использование системных вызовов по созданию и завершению потоков в ОС Linux. Компилировать и выполнить программу, реализующую многопоточность в ОС Linux.

Задание: 1 Основными активными сущностями в ос Linux являются процессы. Процессы в Linux - классические, последовательные процессы. Каждый процесс выполняет одну программу и изначально получает один поток управления. У процесса есть один счетчик команд, который отслеживает следующую исполняемую команду. Linux позволяет процессу создавать дополнительные потоки.

Также Linux представляет собой многозадачную систему, так, что несколько независимых процессов могут работать одновременно. У каждого процесса в Linux есть пользовательская часть, в которой работает программа пользователя, однако, когдаодин из потоков делает системный вызов,то происходит эмулированное прерывание с переключением в режим ядра. После этого поток начинает работу в контексте ядрас другой картой памяти, своим стеком ядра, счетчиком команд в режиме ядра и полным доступом ко всем ресурсам машины. Ядро ОC Linux внутренним образом представляет процессы как задачи при помощи структуры задач task_struct. Процесс с одним потоком представляется одной структурой задач, а многопоточный процесс будет иметь по одной структуре задачи для каждого из потоков пользовательского уровня.

Само ядро является многопоточным и имеет потоки уровня ядра, которые не связаны ни с какими пользовательскими процессами и выполняют код ядра. Для каждого процесса в памяти находится его дескриптор типа task_struct. Он содержит важную информацию, необходимую ядру для управления всеми процессами. Дескриптор процесса создается при создании процесса.

Для совместимости с другими системами unix процессы в Linux идентифицируются при помощи идентификатора процесса PID (ProcessIdentifier). Ядро организует все процессы в двунаправленный список структур задач. Информация в дескрипторе процесса подразделяется на следующие категории:

1.Параметры блокирования (приоритет процесса, израсходованное за последний учитываемый период времени, количество проведенного в режиме ожидания времени)

2.Образ памяти (указатели на сегмент текста, данных и стека) Когда процесса нет в памяти, то здесь так же хранится, как найти его части на диске.

3.Сигналы (маски, указывающие, какие сигналы перехватываются, какие временно заблокированы, и какие находятся в процессе доставки).

4.Машинные регистры. Когда происходит эмулированное прерывание в ядро, то машинные регистры сохраняются здесь

5.Состояние системного вызова (здесь хранится информация

отекущем системном вызове)

6.Таблица дескрипторов файлов (Когда делается системный вызов, использующий дескриптор файла, то файловый дескриптор используется как индекс в этой таблице для обнаружения соответствующей этому файлу структуры данных).

7.Учетные данные (Указатель на таблицу, в которой отслеживается использованное процессом пользовательское и системное время процесса).

8.Стек ядра (фиксированный стек для использования той частью процесса, которая работает в режиме ядра)

9.Разное (текущее состояние процесса, ожидаемое процессом событие, PID процесса, идентификаторы родительского процесса, группы)

2.Взаимодействие процессов

В системе Linux процессы могут общаться друг с другом с помощью следующих структур:

трубы (pipes) – создается канал между двумя процессами, в который один процесс может писать поток байтов, а другой процесс может его читать.

Сигналы (signals) – процессы общаются при помощи программных прерываний. Процессы могут сообщить системе, какие действия следует предпринимать, когда придет сигнал: проигнорировать сигнал, перехватить его, позволить сигналу убить процесс.

SIGABRT– посылается, чтобы прервать процесс и создать дамп памяти

SIGFPE – произошла ошибка при выполнении операции с плавающей точкой

SIGILL – пользователь нажал клавишу delete, чтобы прервать процесс

Процесс может посылать сигналы только членам своей группы, состоящих из его братьев, сестер и прочих потомков.

3.Механизмы создания нового процесса. Системный вызов fork

вродительском процессе (parentprocess), создает новый процесс,

который называется дочерним процессом (child process). У родительского и дочернего процесса есть свои собственные образы памяти. Если впоследствии, родительский процесс изменяет свои переменные, то эти изменения остаются невидимыми для дочернего процесса. Сразу после выполнения системного вызова fork, значения всех соответствующих переменных в обоих процессах одинаковы, но после копирования всего адресного пространства родителя, последующие изменения в одном процессе не влияют на другой. Системный вызов fork возвращает дочернему процессу число 0, а родительскому – отличный от нуля PID дочернего процесса. Оба процесса проверяют возвращаемое значение и действуют соответственно. Открытые файлы используются родительскими и дочерними процессами совместно. Это значит, что, если какой-либо

файл был открыт в родительском процессе, до выполнения системного вызоваfork, то он остается открытым в обоих процессах. Изменения, произведенные с этим файлом любым из процессов видны другому. Если дочерний процесс желает узнать свой идентификатор, то он может воспользоваться системным вызовом getpid. Например, когда дочерний процесс завершается, его родитель получает идентификатор только что завершившегося процесса.

Механизм создания процесса Для дочернего процесса создается новый дескриптор и

пользовательская область, которая заполняется из родительской. Дочерний процесс получает идентификатор, настраивается его карта памяти. Предоставляется доступ к общим файлам. Далее настраиваются регистры дочернего процесса, после чего он готов к запуску.

При вызове fork() происходит следующее:

1.Выделение структуры задач для потомка

2.Заполнение структуры задач потоком данными родителя

3.Выделение памяти для стека и области пользователя дочернего процесса

4.Заполнение области пользователя дочернего процесса

5.Выделение идентификатора для дочернего процесса

6.Настройка дочернего процесса на использование программы родительского процесса

7.Копирование таблицы страниц для данных и стека

8.Настройка совместного использования открытых файлов

9.Копирование регистров родительского процесса в дочерний

процесс

При системном вызове exec() происходит следующее:

1.Поиск исполняемого файла

2.Проверка разрешения на выполнение

3.Чтение и проверка заголовка

4.Копирование аргументов, среды в ядро

5.Освобождение нового адресного пространства

6.Копирование аргументов среды в стек

7.Сбрасывание сигнала

8.Инициализация регистров

Когда выполняется системный вызов fork(), вызывающий процесс выполняет эмулированное прерывание в ядро и создает структуру задачи. Большая часть содержимого дескриптора процесса заполняется значениями из дескриптора родителя, затем Linux ищет доступный идентификатор и обновляет элемент хэш-таблицы идентификаторов, чтобы там был указатель на новую структуру

задачи. Далее система выделяет дочернему процессу его собственные таблицы страниц, но эти таблицы указывают на страницы родительского процесса, помеченного, как доступные только для чтения. Когда дочерний процесс пытается писать в такую страницу, происходит нарушение защиты. Ядро видит это и выделяет дочернему процессу новую копию этой страницы, которую помечает как доступную для чтения и для записи. Таким образом копируются только те страницы, в которые дочерний процесс пишет. Такой механизм называется копированием при записи. После того, как дочерний процесс начинает работу, его код делает системный вызов exec(), задавая имя команды в качестве параметра, при этом ядро находит и проверяет исполняемый файл, копирует в ядро аргументы и освобождает старое адресное пространство. Далее записывается новое адресное пространство. Сигналы сбрасываются, а все регистры устанавливаются в 0. После этого программа готова к работе.

4 Реализация потоков в ОС Linux

В 2000 году в Linux был введен новый системный вызов clone, который размыл отличия между процессами и потоками

Clone(function, stack_ptr, sharing-flags, arf);

Вызов clone создает новый поток либо в новом процессе, либо в текущем, все зависит от флаг аsharing-flags. Если новый поток находится в текущем процессе, то он совместно с существующими потоками использует адресное пространство и каждая запись в любой байт становится видна всем остальным потокам данного процесса. С другой стороны, если адресное пространство совместно не используется, то последующие записи новых потоков не будут видны старым. В обоих случаях новый поток начинает выполнение функции function с аргументом arg в качестве единственного параметра. Также в обоих случаях новый поток получает свой собственный стек, при этом указатель стека инициализируется параметром stack_ptr. Параметр sharing-flags представляет собой битовый массив. Каждый бит может быть установлен независимо от остальных, и каждый из них определят, копирует ли новый поток эту структуру данных или использует ее совместно с вызывающим потоком.

CLOVE_VM 1 - создать новый поток, 0 – создать новый процесс. Если этот бит установлен, но новый поток добавляется к старым. Если этот бит сброшен, то новый поток получает свое собственное адресное пространство.

CLONE_FS 1 – совместно используется рабочий каталог root и флаг umask. 0 – не использовать их совместно. Даже если у нового потока есть адресное пространство, старый и новый потоки будут использовать совместно общие каталоги.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]