- •Основы файловой системы unix
- •Типы файлов
- •Структура файловой системы unix
- •Владельцы файлов
- •Права доступа к файлу
- •Дополнительные атрибуты файлов
- •1 Установить обязательное блокирование файлов при выполнении
- •Устройства
- •Процессы unix
- •Vhand диспетчер страничного замещения
- •Создание и управление процессами
- •Системные функции типа exec
- •Системный вызов _exit
- •Взаимодействие процессов посредством каналов
- •Сигналы
- •Обработка ошибок
- •Пользователи системы, Атрибуты пользователя
- •Форматы исполняемых файлов
- •Файлы отображаемые в памяти
- •Метаданные файла
- •Индексные дескрипторы
- •Имена файлов
- •Недостатки и ограничения файловой системы s5fs
- •Файловая система ffs (Fast File System)
- •Каталоги ffs
- •Сравнение процессов может быть произведено с использованием понятия "трасса" порядок и длительность пребывания процесса в допустимых состояниях на интервале существования.
- •Ресурсы, Понятие и классификация
- •Решение №1.
- •Сообщенная задача взаимного исключения
- •Синхронизирующие примитивы
- •V(свободно);
- •Взаимодействие через переменные состояния
- •Пример применения приоритетного правила
- •Проблема тупиков
- •Алгоритм банкира
- •Основными вопросами при решении такой задачи являются:
- •Применение алгоритма банкира
- •Основные направления совершенствования структуры
- •Системы с параллельным выполнением операций. Параллельные процессы.
- •Схемы типа окмд
- •Особенности организации процессоров по принципу окмд (одиночный поток команд – множественный поток данных)
- •Мультипроцессорные системы
- •Транспьютеры
- •Центральный процессор
- •Распределение памяти в транспьютерах
- •Диспетчеризация процессов
- •Ввод / вывод
Системный вызов _exit
#include <unistd.h>
void _exit(int exit_code);
Вызов системного вызова _exit приводит к освобождению сегмента данных, сегмента стека и закрытию всех открытых дескрипторов файлов для процесса, который вызвал _exit;
Но запись в таблице процессов, в которой был зарегистрирован этот процесс, не удаляется, т.е. она ещё не может быть занята другим процессом. Процесс переходит в состояние “зомби”, т.к. его дальнейшее выполнение не планируется. Удалить запись может только родительский процесс с помощью вызова wait и waitpid.
Если процесс порождает сына и заканчивается раньше, чем процесс-сын, то системный процесс init становится управляющим для процесса-сына, и после его завершения удаляет запись о нём в таблице процессов.
Аргумент _exit код завершения процесса, причём родителю передаются только 8 младших бит. Нулевое значение свидетельствует об успешном завершении, ненулевое о завершении процесса с ошибкой или по причине какой-либо ситуации.
Взаимодействие процессов посредством каналов
#include <unistd.h>
int pipe(int fifo[2]);
Для создания коммуникационного канала между процессами используется системный вызов pipe, который создаёт файл канала, служащий временным буфером и использующийся для того, чтобы процесс мог записывать туда данные для других процессов и читать данные для себя. Файлу канала имя не присваивается => “неименованный канал”. Канал освобождается после того, как все процессы закроют дескриптор, ссылающийся на этот канал.
Аргумент pipe массив из двух целых чисел.
В большинстве UNIX-систем каналы однонаправленные, т.е. для чтения данных из канала используется fifo[0], а для записи fifo[1]
К данным, хранящимся в канале, доступ производится последовательно по принципу First In First Out. Процесс не может использовать функции позиционирования в канале. Данные удаляются из канала сразу после считывания.
Можно определить две типовые схемы взаимодействия.
-
Родитель <-> сын: родитель вызывает pipe для создания канала, а затем с помощью fork порождает сына. Т.к. порожденный процесс имеет копию дескрипторов файлов процесса-отца, то теперь процесс-отец и процесс-сын могут взаимодействовать через fifo[0] и fifo[1]
-
Брат <-> брат: родитель вызывает pipe, а затем порождает 2 или более сыновей-братьев. Процессы-браться взаимодействуют между собой через fifo[0] и fifo[1]
Буфер, связанный с каналом, имеет конечный размер. При попытке записать данные в уже заполненный канал, ядро заблокирует процесс до тех пор, пока другой процесс не считает из канала достаточное количество данных, чтобы заблокированный процесс смог возобновить запись.
#include <iosream.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{ pid_t child_pid, pid; int status, fifo[2], char buf[80];
if (pipe(fifo)==-1) printf (“Ошибка pipe!”); _exit(1);
switch(child_pid=fork())
{ case -1 : printf (“Ошибка fork!”); _exit(2);
case 0 : close(fifo[0]); printf (“Процесс сын %d завершился”, getpid())); close(fifo[1]); _exit(0);}
close(fifo[1]);
while (read(fifo[0],buf,80)) printf(“\n %s”,buf);
close(fifo[0]);
if (waitpid(child_pid, &status, 0)==child_pid && WIFEXITED(status));
return(WEXITSTATUS(status);
return(3); }
Количество процессов, которые могут присоединиться к каналу, принципиально не ограничено. Однако если два или более процессов записывают в канал данные, то величина записи каждого из процессов ограничена определенной в системе величиной. Через некоторое время найдется процесс, считывающий данные из канала, после этого опять очередь перейдёт к данному процессу и он дозапишет информацию.
Для предотвращения такого недостатка коммуникационный канал обычно делают однонаправленным и используют его для связи между двумя процессами, причем один процесс является отправителем, а другой получателем. Если оба процесса требуют при взаимодействии как операции передачи, так и операции приема, то целесообразно для связи между ними создать два канала.
Если дескриптора файла, связанного с записывающей стороной канала не существует, то эта сторона считается закрытой и любой процесс, пытающиеся считать данные из канала, получает оставшиеся в нем данные. Если все данные прочитаны, то получает признак конца файла. Если же не существует дескриптора файла, связанного с читающей стороной канала, а процесс пытается записать данные в канал, то ядро формирует для данного канала сигнал SIGPIPE. Действие по умолчанию на этот сигнал завершение процесса.
В этом примере родительский процесс определяется как получатель, который читает сообщения порожденного процесса с помощью дескриптора fifo[0], причем родительский процесс сначала закрывает на запись дескриптор fifo[1]. Это требуется для того, чтобы записывающая сторона канала закрылась, когда процесс-сын после передачи данных в канал закрывает свой дескриптор fifo[1]. Процесс-сын закрывает дескриптор на чтение, а потом производит запись данных в канал, а родитель читает данные, а потом закрывает канал на чтение. Если сын не закроет канал, отец не получит признака конца файла.