
- •Дайте определение диспетчеру памяти и адресным пространствам. Поясните механизм использования базового и ограничительного регистров.
- •Приведите классификацию ос
- •Проведите обзор файловых систем (ntfs и ufs) Структура ntfs
- •Структура ufs
- •Дайте определение ос, опишите функции ос
- •Опишите основные этапы развития ос
- •Дайте определение виртуальной памяти, страничной организации памяти. Опишите структуру таблиц страниц
- •Опишите механизмы работы буфера быстрого преобразования адреса, многоуровневых и инвертированных таблицы страниц.
- •Дайте определение процессу и опишите блок управления процессом.
- •Опишите механизмы создания и уничтожения процессов Создание процесса
- •Удаление процесса
- •Опишите основные состояния процессов и возможные переходы между ними. Дайте определение переключению контекста.
- •Опишите механизмы диспетчеризации процессов.
- •Дайте определение свопинг. Опишите механизм управления свободной памятью при свопинге (битовые матрицы)
- •Опишите механизм управления свободной памятью при свопинге (связные списки и поиск по ним)
- •Проведите обзор аппаратного обеспечения пк
- •Дайте определение состязательной ситуации, критической области. Поясните механизм работы барьеров и обмена сообщениями
- •Проведите обзор файловых систем (общая информация и fat)
- •Опишите алгоритм замещения страниц wsClock
- •Опишите алгоритм замещения страниц lru
- •Опишите алгоритм замещения страниц ws.
- •Опишите алгоритм замещения страниц Clock
- •Опишите алгоритм замещения страниц nru
- •Опишите оптимальный алгоритм замещения страниц
- •Опишите алгоритм замещения страниц Second Chance
- •Опишите алгоритм замещения страниц fifo
- •Опишите алгоритм диспетчеризации процессов rr
- •Опишите алгоритм диспетчеризации процессов srtf
- •Опишите алгоритм диспетчеризации процессов fcfs
- •Опишите алгоритм диспетчеризации процессов sjf
- •Перечислите основные команды языка сценариев bat
- •Решите задачу производителя/потребителя через sleep и wakeup
- •Решите задачу производителя/потребителя через алгоритм Петерсона
- •Решите задачу производителя/потребителя через семафоры и мьютексы
- •Решите задачу обедающих философов через семафоры и мьютексы
Решите задачу обедающих философов через семафоры и мьютексы
Пять философов сидят за круглым столом, и у каждого из них есть тарелка спагетти. Эти спагетти настолько скользкие, что есть их можно только двумя вилками. Между каждыми двумя тарелками лежит одна вилка.
Решение не вызывает взаимной блокировки и допускает максимум параллелизма для произвольного числа философов. В нем используется массив state, в котором отслеживается, чем занимается философ: ест, размышляет или пытается поесть (пытается взять вилки). Перейти в состояние приема пищи философ может, только если в этом состоянии не находится ни один из его соседей. Соседи философа с номером i определяются макросами LEFT и RIGHT. Иными словами, если i равен 2, то LEFT равен 1, а RIGHT равен 3.
#define N 5 /* количество философов */
#define LEFT (i+N−1) %N /* номер левого соседа для i-го философа */
#define RIGHT (i+1) %N /* номер правого соседа для i-го философа */
#define THINKING 0 /* философ размышляет */
#define HUNGRY 1 /* философ пытается взять вилки */
#define EATING 2 /* философ ест спагетти */
typedef int semaphore; /* Семафоры — особый вид целочисленных переменных */
int state[N]; /* массив для отслеживания состояния каждого философа */
semaphore mutex = 1; /* Взаимное исключение входа в критическую область */
semaphore s[N]; /* по одному семафору на каждого философа */
void philosopher(int i) /* i – номер философа (от 0 до N−1) */
{
while (TRUE) { /* бесконечный цикл */
think(); /* философ размышляет */
take_forks(i); /* берет две вилки или блокируется */
eat(); /* ест спагетти */
put_forks(i); /* кладет обе вилки на стол */
} }
void take_forks(int i) /* i – номер философа (от 0 до N−1) */
{
down(&mutex); /* вход в критическую область */
state[i] = HUNGRY; /* запись факта стремления философа поесть */
test(i); /* попытка взять две вилки */
up(&mutex); /* выход из критической области */
down(&s[i]); /* блокирование, если вилки взять не удалось */ }
void put_forks(i) /* i – номер философа (от 0 до N−1) */ {
down(&mutex); /* вход в критическую область */
state[i] = THINKING; /* философ наелся */
test(LEFT); /* проверка готовности к еде соседа слева */
test(RIGHT); /* проверка готовности к еде соседа справа */
up(&mutex); /* выход из критической области */
}
void test(i) /* i – номер философа (от 0 до N−1) */ {
if (state[i] == HUNGRY && state[LEFT] != EATING && state[RIGHT] != EATING) {
state[i] = EATING;
up(&s[i]); } }
В программе используется массив семафоров, по одному семафору на каждого философа, поэтому голодный философ может блокироваться, если нужная ему вилка занята. Обратите внимание на то, что каждый процесс в качестве своей основной программы запускает процедуру philosopher, но остальные процедуры: take_forks, put_ forks и test — это обычные процедуры, а не отдельные процессы.
Решите задачу производителя/потребителя через команду TSL
Поставить enter_region вместо down вход в критическую область
Поставить leave region вместо up выход из критической области
Решите задачу обедающих философов через команду TSL
Поставить enter_region вместо down вход в критическую область
Поставить leave region вместо up выход из критической области
Решите задачу читателя/писателя через команду TSL
Поставить enter_region вместо down вход в критическую область
Поставить leave region вместо up выход из критической области
Решите задачу читателя/писателя через семафоры и мьютексы
Задача читателей и писателей: моделируется доступ к базе данных. Представим, к примеру, систему бронирования авиабилетов, в которой есть множество соревнующихся процессов, желающих обратиться к ней для чтения и записи. Вполне допустимо наличие нескольких процессов, одновременно считывающих информацию из базы данных, но, если один процесс обновляет базу данных (проводит операцию записи), никакой другой процесс не может получить доступ к базе данных даже для чтения информации.
В коде первый читатель для получения доступа к базе данных выполняет в отношении семафора db операцию down. А все следующие читатели просто увеличивают значение счетчика rc. Как только читатели прекращают свою работу, они уменьшают значение счетчика, а последний из них выполняет в отношении семафора операцию up, позволяя заблокированному писателю, если таковой имеется, приступить к работе. В представленном здесь решении есть одна достойная упоминания недостаточно очевидная особенность. Допустим, что какой-то читатель уже использует базу данных и тут появляется еще один читатель. Поскольку одновременная работа двух читателей разрешена, второй читатель допускается к базе данных. По мере появления к ней могут быть допущены и другие дополнительные читатели. Теперь допустим, что появился писатель. Он может не получить доступа к базе данных, поскольку писатели должны иметь к ней исключительный доступ, поэтому писатель приостанавливает свою работу. Позже появляются и другие читатели. Доступ дополнительным читателям будет открыт до тех пор, пока будет активен хотя бы один читатель. Вследствие этой стратегии, пока продолжается наплыв читателей, все они будут получать доступ к базе по мере своего прибытия. Писатель будет приостановлен до тех пор, пока не останется ни одного читателя. Если новый читатель будет прибывать, скажем, каждые 2 с и каждый читатель затратит на свою работу по 5 с, писатель доступа никогда не дождется. Чтобы предотвратить такую ситуацию, программу можно слегка изменить: когда писатель находится в состоянии ожидания, то вновь прибывающий читатель не получает немедленного доступа, а приостанавливает свою работу и встает в очередь за писателем. При этом писатель должен дождаться окончания работы тех читателей, которые были активны при его прибытии, и не должен пережидать тех читателей, которые прибывают после него. Недостаток этого решения заключается в снижении производительности за счет меньших показателей параллельности в работе.
typedef int semaphore; /* напрягите свое воображение */
semaphore mutex = 1; /* управляет доступом к 'rc' */
semaphore db = 1; /* управляет доступом к базе данных */
int rc = 0; /* количество читающих или желающ. читать процессов*/
void reader(void)
{
while (TRUE) { /* бесконечный цикл */
down(&mutex); /* получение исключительного доступа к ‘rc’ */
rc = rc + 1; /* теперь на одного читателя больше */
if (rc == 1) down(&db); /* если это первый читатель... */
up(&mutex); /* завершение исключительного доступа к ‘rc’ */
read_data_base( ); /* доступ к данным */
down(&mutex); /* получение исключительного доступа к ‘rc’ */
rc = rc − 1; /* теперь на одного читателя меньше */
if (rc == 0) up(&db); /* если это последний читатель... */
up(&mutex); /* завершение исключительного доступа к ‘rc’ */
use_data_read(); /* некритическая область */ } }
void writer(void)
{
while (TRUE) { /* бесконечный цикл */
think_up_data( ); /* некритическая область */
down(&db); /* получение исключительного доступа */
write_data_base( ); /* обновление данных */
up(&db); /* завершение исключительного доступа */
} }