Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
os-linux.doc
Скачиваний:
1
Добавлен:
01.05.2025
Размер:
283.65 Кб
Скачать

Задание

Построить генеалогическое дерево из 4-х поколений процессов. Количество процессов во 2-ом поколении – А (см. табл. 1), в 3-ем – Е, в 4-ом – D. Процессы должны существовать  1 секунду и выводить:

  • собственный идентификатор;

  • идентификатор предка;

  • статистику жизни.

Вопросы коллоквиума

  1. Системный вызов fork возвращает.

  2. Чем различаются порожденный и предковый процессы.

  3. «Папы», «дети», «сироты» и «зомби».

  4. Что делает системный вызов _exit.

  5. Предназначение системного вызова wait.

  6. Предназначение системного вызова exec.

  7. В каком случае процесс переводиться в режим ядра.

«Трубы» Использование программных каналов

Процессы могут обмениваться между собой информацией через файлы. Существуют файлы с необычным поведением - так называемые FIFO-файлы (first in, first out), ведущие себя подобно очереди. У них указатели чтения и записи разделены. Работа с таким файлом напоминает проталкивание шаров через трубу - с одного конца мы вталкиваем данные, с другого конца - вынимаем их. Операция позиционирования указателя чтения - lseek(), неприменима к FIFO-файлам, данные удаляются из канала сразу же после их считывания. FIFO-файл создается системным вызовом:

#include <sys/types.h>

#include <sys/stat.h>

mknod( имяФайла, S_IFIFO | 0666, 0 );

где 0666 - коды доступа к файлу.

При помощи FIFO-файла могут общаться даже не родственные процессы.

Разновидностью FIFO-файла является безымянный FIFO-файл, предназначенный для обмена информацией между процессом-отцом и процессом-сыном. Такой файл - канал связи как раз и называется термином "труба" или pipe.

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

#include <unistd.h>

int pipe (int fifo[2]);

Аргумент fifo является массивом, состоящим из двух целых чисел, присваиваемых ему интерфейсом pipe. В большинстве систем UNIX канал является однонаправленным, т.е. для чтения данных из канала процесс использует дескриптор файла fifo[0], а для записи данных в канал — другой дескриптор файла, fifo[1].

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

  • Порожденные процессы-братья: родительский вызывает pipe для создания канала, затем порождает два или больше процессов-братьев. Порожденные процессы могут сообщаться по каналу посредством своих дескрипторов fifo[0] и fifo[1].

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

Коммуникационный канал обычно делают однонаправленным и устанавливают его только между двумя процессами, чтобы один процесс являлся отправителем, а другой — получателем. Если два процесса, например А и В, нуждаются в двунаправленном коммуникационном канале, они создадут два канала: один для записи данных процесса А в процесс В, другой для осуществления обратной операции. Количество процессов, которые могут параллельно присоединяться к любому концу канала, не ограничено.

Если дескриптора файла, связанного с записывающей стороной канала, не существует, то последняя считается "закрытой" и любой процесс, пытающийся считать данные из канала, получает оставшиеся в нем данные. Однако если все данные из канала уже выбраны, процесс, пытающийся продолжать чтение данных из канала, получает признак конца файла (системный вызов read возвращает нулевое значение). С другой стороны, если не существует дескриптора файла, связанного с читающей стороной канала, а процесс пытается записать данные в канал, он получает от ядра сигнал SIGPIPE (разорванный канал). Это происходит потому, что данные, записанные в канал, не могут быть выбраны процессом и, следовательно, операция записи считается недопустимой. Процесс, производящий запись, будет "наказан" этим сигналом (действие этого сигнала по умолчанию — преждевременное завершение процесса).

В приведенном ниже примере исполнимый файл ./creator создаёт две трубы, двоих сыновей и ждет окончания их работы. ./client1 в цикле читает из файла строки и посылает их в трубу. ./clent2 читает из трубы и записывает в файл строки. Оба процесса дописывают строки. Вторая труба не используется.

/*creator.c*/

#include<stdio.h>

#include<sys/types.h>

#include<sys/stat.h>

#include <sys/errno.h>

extern int errno;

#define chan1 "fifo.1"

#define chan2 "fifo.2"

#define PERM 0666

main ()

{

int fdw1,fdw2,fdw3,i,st;

if((mknod(chan1, S_IFIFO | PERM, 0) < 0) && (errno != EEXIST))

printf ("Can't create fifo 1: %s, chan1");

if((mknod(chan2, S_IFIFO | PERM, 0) < 0) && (errno != EEXIST))

printf ("Can't create fifo 2: %s, chan2");

if(fork()==0)

execvp("./client1",NULL);

if(fork()==0)

execvp("./client2",NULL);

while(i=wait(&st)>0);

unlink(chan1);

unlink(chan2);

}

/*client1.c*/

#include <stdio.h>

#define chan1 "fifo.1"

#define MAXBUFF 1024

main ()

{

int fdr1, i;

FILE *fpA;

char buff[MAXBUFF];

fpA=fopen("pi_ser.txt","r") ;

if ((fdr1 = open(chan1,1)) < 0)

printf("client1 не нашел трубы\n");

for(i=0;i<=5;i++)

{

fgets(buff,MAXBUFF,fpA);

strcat(buff,"+client1 читает из файла pi_ser.txt\n");

write(fdr1,buff,MAXBUFF);

}

close(fdr1);

fclose(fpA);

exit(0);

}

/*client2.c*/

#include <stdio.h>

extern int errno;

#define chan1 "fifo.1"

#define MAXBUFF 1024

main ()

{

int i, fdr1;

FILE *fpA;

char buff[MAXBUFF];

fpA=fopen("text.txt","w+");

if ((fdr1 = open(chan1, 0)) < 0)

printf("client2 не нашел трубы\n");

for(i=0;i<=5;i++)

{

read(fdr1,buff,MAXBUFF);

strcat(buff,"+client2 читает из трубы\n");

fprintf(fpA,buff);

}

fclose(fpA);

close(fdr1);

exit(0);

}

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