Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
шпора UNIX.doc
Скачиваний:
29
Добавлен:
15.06.2014
Размер:
530.43 Кб
Скачать

Системный вызов _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. Процесс не может использовать функции позиционирования в канале. Данные удаляются из канала сразу после считывания.

Можно определить две типовые схемы взаимодействия.

  1. Родитель <-> сын: родитель вызывает pipe для создания канала, а затем с помощью fork порождает сына. Т.к. порожденный процесс имеет копию дескрипторов файлов процесса-отца, то теперь процесс-отец и процесс-сын могут взаимодействовать через fifo[0] и fifo[1]

  2. Брат <-> брат: родитель вызывает 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]. Процесс-сын закрывает дескриптор на чтение, а потом производит запись данных в канал, а родитель читает данные, а потом закрывает канал на чтение. Если сын не закроет канал, отец не получит признака конца файла.