Главная » Просмотр файлов » Лекции в ворде

Лекции в ворде (1115146), страница 13

Файл №1115146 Лекции в ворде (Лекции в ворде) 13 страницаЛекции в ворде (1115146) страница 132019-05-08СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 13)

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

Напоминаю, что цель нашего курса не есть изучение того, как реализована та или иная функция в той или иной версии системы UNIX. Мы хотим посмотреть, как это можно сделать, чтобы у вас не возникало ощущения чуда, когда вы видите работающую операционную систему, и вас не пробирала дрожь, что это нечто сверхъестественное. Все предельно просто. Есть правило: чем более системной является программа, тем более прозрачными должны быть алгоритмы и использованные идеи. Мудреные программы живут с трудом, и это подтверждено практикой. Прозрачные программы живут долго. Пример - UNIX - прозрачная программа, и пример Windows - программа, построенная на очень высоком уровне, но там нет прозрачности на всех уровнях, и, к сожалению, система имеет достаточное количество особенностей, которые приводят к непредсказуемым результатам ее работы. Так везде. Если мы посмотрим языки программирования - был совершенно фантастический проект языка АДА, когда на конкурсной основе были образованы несколько профессиональных команд, которые разрабатывали язык конца XX века. Он должен был уметь делать все. Получилась очень красивая вещь. С профессиональной точки зрения, этот язык во всем хорош, но он не нашел практического применения, потому что сложен. Совершенно «бездарный» язык Си существует и еще долго будет существовать. То же самое можно сказать о языках Вирта (это дядя, который придумал Паскаль, Модулу и Оберон) - они тоже не прижились.

Процессы и взаимодействие процессов

С этого момента времени мы начинаем долго и упорно рассматривать различные способы взаимодействия процессов в операционной системе UNIX. Маленькое техническое добавление. Я сейчас вам продекларирую две системные функции, которыми мы будем пользоваться впоследствии. Это функции дублирования файловых дескрипторов (ФД).

int dup(fd); int dup2(fd, to_fd);

int fd; int fd, to_fd;

Аргументом функции dup является файловый дескриптор открытого в данном процессе файла. Эта функция возвращает -1 в том случае, если обращение не проработало, и значение, большее либо равное нулю, если работа функции успешно завершилась. Работа функции заключается в том, что осуществляется дублирование ФД в некоторый свободный ФД, т.е. можно как бы продублировать открытый файл.

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

Пример:

int fd;

char s[80];

fd = open(«a.txt»,O_RDONLY);

dup2(fd,0);

close(fd);

gets(s,80);

Программа открывает файл с именем a.txt только на чтение. ФД, который будет связан с этим файлом, находится в fd. Далее программа обращается к функции dup2, в результате чего будет заменен стандартный ввод процесса на работу с файлом a.txt. Далее можно закрыть дескриптор fd. Функция gets прочтет очередную строку из файла a.txt. Вы видите, что переопределение осуществляется очень просто.

Программные каналы. Сначала несколько слов о концепции. Есть два процесса, и мы хотим организовать взаимодействие между этими процессами путем передачи данных от одного процесса к другому. В системе UNIX для этой цели используются т.н. каналы. С точки зрения программы, канал есть некая сущность, обладающая двумя файловыми дескрипторами. Через один ФД процесс может писать информацию в канал, через другой ФД процесс может читать информацию из канала. Так как канал это нечто, связанное с файловыми дескрипторами, то канал может передаваться по наследству сыновним процессам. Это означает, что два родственных процесса могут обладать одним и тем же каналом. Это означает, что если один процесс запишет какую-то информацию в канал, то другой процесс может прочесть эту информацию из этого же канала.

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

Давайте посмотрим, как эти концепции реализуются в системе. Есть функция pipe. Аргументом этой функции должен быть указатель на массив двух целых переменных.

int pipe(pipes);

int pipes[2];

Нулевой элемент массива после обращения к функции pipe получает ФД для чтения, первый элемент этого массива получает ФД для записи. Если нет свободных ФД, то эта функция возвращает -1. Признак конца файла для считывающего дескриптора не будет получен до тех пор, пока не закрыты все дескрипторы, связанные с записью в этот канал. Рассмотрим небольшой пример:

char *s = «Это пример »;

char b[80];

int pipes[2];

pipe(pipes);

write(pipes[1],s, strlen(s)+1);

read(pipes[0],s, strlen(s)+1);

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

main()

{

int fd[2];

pipe(fd); /* в отцовском процессе образуем два дескриптора канала */

if (fork()) /* образуем процесс-сын, у которого будут те же дескрипторы */

{ /* эта часть программы происходит в процессе-отце */

dup2(fd[1],1); /* заменяем стандартный вывод выводом в канал */

close(fd[1]); /* закрываем дескрипторы канала */

close(fd[0]); /* теперь весь вывод итак будет происходить в канал */

execl(«/bin/ls»,«ls»,(char*)0); /* заменяем тело отца на ls */

} /* отсюда начинает работать процесс-сын */

dup2(fd[0],0); /* в процессе сыне все делаем аналогично */

close(fd[0]);

close(fd[1]);

execl(«/bin/wc»,«wc»,(char*)0);

}

Этот пример связывает конвейером две команды - ls и wc. Команда ls выводит содержимое каталога, а команда wc подсчитывает количество строк. Результатом выполнения нашей программы будет подсчет строк, выведенных командой ls.

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

Мы говорили о том, что для того чтобы канал работал корректно, и читающий дескриптор получил признак конца файла, должны быть закрыты все пишущие дескрипторы. Если бы в нашей программе не была бы указана выделенная строка, то процесс, связанный с wc завис бы, потому что в этом случае функция, читающая из канала, не дождется признака конца файла. Она будет ожидать его бесконечно долго. В процессе отце подчеркнутую строку можно было бы не указывать, т.к. дескриптор закрылся бы при завершении процесса, а в процессе сыне такая строка нужна. Т.е. вывод таков: перед завершением работы должны закрываться все дескрипторы каналов, связанные с записью.

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

Лекция №14

Сигналы в системе UNIX

Рассмотрим взаимодействие между процессами с помощью приема-передачи сигналов. Мы уже говорили о том, что в системе UNIX можно построить аналогию механизма прерываний из некоторых событий, которые могут возникать при работе процессов.

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

  • некоторое событие внутри программы, например, деление на ноль или переполнение;

  • событие, связанное с приходом некоторой информации от устройства, например, событие, связанное с передачей от клавиатуры комбинации “Ctrl+C”;

  • событие, связанное с воздействием одного процесса на другой, например, “SIG_KILL”.

Система имеет фиксированный набор событий, которые могут возникать. Каждое событие имеет свое уникальное имя; эти имена обычно едины для всех версий UNIX. Такие имена называются сигналами.

Перечень сигналов находится в include-ôàéëå “signal.h”.

Есть сигналы, которые присутствуют практически во всех UNIX, но также есть сигналы, специфичные лишь для конкретной версии UNIX (FreeBSD, SCO UNIX, Linux, ...) Например, в версии BSD есть сигнал приостановки работы процесса, реакцией на который является замораживание процесса, а есть сигнал, который размораживает процесс. Это сигнал FreeBSD версии.

Прототип функции обработки сигнала:

void (* signal (sig, fun)) ()

int sig;

void (* fun) ();

При обращении к signal мы передаем:

sig - имя сигнала;

fun - указатель на функцию, которая будет обрабатывать событие, связанное с возникновением этого сигнала. Функция signal возвращает указатель на предыдущую функцию обработки данного сигнала.

Мы говорили о том, что событие, связанное с возникновением сигнала может быть обработано в системе тремя способами:

  1. SIG_DEF - стандартная реакция на сигнал, которая предусмотрена системой;

  2. SIG_IGN - игнорирование сигнала (следует отметить, что далеко не все сигналы можно игнорировать, например, SIG_KILL);

  3. Некоторая пользовательская функция обработки сигнала.

Соответственно, указывая либо имена предопределенных констант, либо указатель на функцию, которую мы хотим определить как функцию-обработчик сигнала, можно предопределить реакцию на тот или иной сигнал. Установка обработки сигнала происходит одноразово, это означает то, что если мы установили некоторую обработку, то по этому правилу будет обработано только одно событие, связанное с появлением данного сигнала. И при входе в функцию-обработчика устанавливается стандартная реакция на сигнал. Возврат из функции-обработчика происходит в точку прерывания процесса.

Приведем пример программы “Будильник”. Средствами ОС мы будем “заводить” будильник. Функция alarm инициализирует появление сигнала SIG_ALRM.

main ()

{

char s[80];

signal(SIG_ALRM, alrm); /* установка режима связи с событием SIG_ALRM на функцию alrm */

alarm(5); /* заводим будильник */

printf(“Введите имя \n”);

for (;;)

{

printf(“имя:”);

if (gets(s,80) != NULL) break;

};

printf(“OK! \n”);

}

alrm ()

{

printf(“\n жду имя \n”);

alarm(5);

signal (SIG_ALRM,alrm);

}

В начале программы мы устанавливаем реакцию на сигнал SIG_ALRM - функцию alrm, далее мы заводим будильник, запрашиваем “Введите имя” и ожидаем ввода строки символов. Если ввод строки задерживается, то будет вызвана функция alrm, которая напомнит, что программа “ждет имя”, опять заведет будильник и поставит себя на обработку сигнала SIG_ALRM еще раз. И так будет до тех пор, пока не будет введена строка.

Здесь имеется один нюанс: если в момент выполнения системного вызова возникает событие, связанное с сигналом, то система прерывает выполнение системного вызова и возвращает код ответа, равный «-1». Это мы можем также проанализировать по функции errno.

Надо отметить, что одноразово устанавливается только “свой” обработчик. Дефолтный обработчик или игнорирование устанавливается многоразово, то есть его не надо каждый раз подтверждать после обработки сигнала.

Еще две функции, которые необходимы нам для организации взаимодействия между процессами:.…

1) int kill(int pid, sig) - это функция передачи сигнала процессу. Она работает следующим образом: процессу с номером pid осуществляется попытка передачи сигнала, значение которого равно sig. Соответственно, сигнал может быть передан в рамках процессов, принадлежащих к одной группе. Код ответа: -1, если сигнал передать не удалось, пояснение опять же можно найти в errno. Функция kill может использоваться для проверки существования процесса с заданным идентификатором. Если функция выполняется с sig=0, то это тестовый сигнал, который определяет: можно или нет передать процессу сигнал; если можно, то код ответа kill отличен от «-1». Если pid=0, то заданный сигнал передается всем процессам, входящим в группу.

2) int wait(int *wait_ret) - ожидание события в сыновнем процессе. Если сыновнего процесса нет, то управление возвращается сразу же с кодом ответа «-1» и расшифровкой в errno. Если в процессе-сыне возникло событие, то анализируются младшие 16 бит в значении wait_ret:

а) Если сын приостановлен (трассировка или получение сигнала), тогда старшие 8 бит wait_ret - êîä ñèãíàëà, êîòîðûé ïîëó÷èë ïðîöåññ-ñûí, а младшие содержат код 0177.

Характеристики

Тип файла
Документ
Размер
1,85 Mb
Тип материала
Высшее учебное заведение

Список файлов лекций

Свежие статьи
Популярно сейчас
Почему делать на заказ в разы дороже, чем купить готовую учебную работу на СтудИзбе? Наши учебные работы продаются каждый год, тогда как большинство заказов выполняются с нуля. Найдите подходящий учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6314
Авторов
на СтудИзбе
312
Средний доход
с одного платного файла
Обучение Подробнее