Вы на НеОфициальном сайте факультета ЭиП

На нашем портале ежедневно выкладываются материалы способные помочь студентам. Курсовые, шпаргалки, ответы и еще куча всего что может понадобиться в учебе!
Главная Контакты Карта сайта
 
Где мы?
» » » Операционные системы. Каналы.

Реклама


Операционные системы. Каналы.

Просмотров: 2064 Автор: admin
Лабораторная работа № 3.2
Каналы
Цель работы: дать учащимся представления об каналах и примерах ихэксплуатации.
Методический материал
Каналы — это коммуникационное устройство, допускающее однонаправленноевзаимодействие.
Данные, записываемые на «входном» конце канала, читаются на «выходном» егоконце.
Каналы являются последовательными устройствами: данные всегда читаютсяв том порядке, в котором они были записаны. Канал обычно используется каксредство связи между двумя потоками одного процесса или между родительским идочерним процессами.
В интерпретаторе команд канал создается оператором | . Например,показанная ниже команда заставляет интерпретатор запустить два дочернихпроцесса, один — для программы ls, второй для команды less:
%ls | less
Интерпретатор также формирует канал, соединяющий стандартный выходнойпоток подпроцесса ls со стандартным входным потоком подпроцесса less. Такимобразом, имена файлов, перечисляемые программой ls, посылаются программепостраничной разбивки less в том порядке, в котором они отображались бы натерминале.
Информационная емкость канала ограничена. Если пишущий процесспомещает данные в канал быстрее, чем читающий процесс их извлекает, и буферканала переполняется, то пишущий процесс блокируется до тех пор, пока буфер неосвободится. И наоборот: если читающий процесс обращается к каналу, в которыйеще не успели поступить данные, он блокируется в ожидании данных. Такимобразом, канал автоматически синхронизирует оба процесса.
Программно канал создается с помощью функции pipe(). Ей необходимопередать массив из двух целых чисел. В элементе с индексом 0 функция сохранитдескриптор фала, соответствующего выходному концу канала, а в элементе синдексом 1 сохраняется дескриптор файла, соответствующего входному концуканала. Рассмотрим следующий фрагмент программы:
int pipe_fds[2];
int read_fd;
int write_fd;
pipe (pipe_fds);
read_fd = pipe_fds[0];
write_fd = pipe_fds[1];
Данные записываемые в файл write_fd, могут быть прочитаны из файла read_fd.
Функция pipe() создает два файловых дескриптора, которые действительны только втекущем процессе и его потомках. Эти дескрипторы нельзя передать постороннемупроцессу. Дочерний процесс получает копии дескрипторов после завершенияфункции fork().
В программе, показанной в листинге 1, родительский процесс записывает вканал строку, а дочерний процесс ее читает. С помощью функции fdopen() файловыедескрипторы приводятся к типу FILE*. Благодаря этому появляется возможностьиспользовать высокоуровневые функции ввода-вывода, такие как printf(), fgets().Листинг №1.
/*pipe.c Общение с дочерним процессом посредством канала.*/ /
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h> #
/*Запись указанного числа копий (COUNT) сообщения (MESSAGE)
в поток (STREAM) с паузой между каждой операцией.*/ в
void writer (const char * message, int count, FILE* stream)
{
for (; count > 0; --count)
{ {
/*Запись сообщения в поток с немедленным "выталкиванием" из буфера.*/ /
fprintf (stream, "%s\n", message);
fflush (stream); f
/*Небольшая пауза*/ /
sleep (1);
}
} }
/*Чтение строк из потока, пока он не опустеет.*/ /
void reader (FILE* stream)
{
char buffer[1024]; ]
/*Чтение данных, пока не будет обнаружен конец потока.
Функция fgets() завершается, когда встречает символ
новой строки или признака конца файла*/ н
while (!feof (stream) && !ferror (stream) && fgets (buffer,sizeof(buffer),stream)!= NULL)
fputs (buffer, stdout); f
} } }
int main ()
{
int fds[2];
pid_t pid; /*Создание канала. Дескрипторы обоих концов канала помещаются в массивfds. */ f
pipe (fds);p
/*Порождение дочернего процесса. */ /
pid = fork ();
if (pid == (pid_t) 0)
{
FILE* stream;
close(fds[1]); c
/*Приводим дескриптор выходного конца канала к типу FILE*
и читаем данные из канала */ и
stream = fdopen (fds[0], "r");
reader (stream);
close(fds[0]);
} }
else
{ {
/*Это родительский процесс*/ /
FILE *stream; F
/*Закрываем копию выходного конца канала*/ /
close (fds[0]); ]
/*Приводим дескриптор выходного конца канала к типу FILE* и записываемданные в канал*/ д
stream = fdopen (fds[1], "w");
writer ("Hello World.", 5, stream);
close (fds[1]);
}
return 0;
}
Сначала в программе объявляется массив fds, состоящий из двух целыхчисел. Функция pipe() создает канал и помещает в массив дескрипторы входного ивыходного концов канала. Затем функция fork() порождает дочерний процесс. Послезакрытия выходного конца канала родительский процесс начинает записывать строкив канал. Дочерний процесс читает строки из канала, предварительно закрывает еговходной конец.
Обратите внимание на то, что в функции writer() родительский процесспринудительно «выталкивает» буфер канала, вызывая функцию fflush(). Без этогострока могла бы «застрять» в буфере и отправиться в канал только послезавершения родительского процесса.
При вызове команды ls | less функция fork() выполняется дважды: один раз —для дочернего процесса ls, второй раз — для дочернего процесса less. Обапроцесса наследует копии дескрипторов канала, поэтому могут общаться друг сдругом.Часто требуется создать дочерний процесс и сделать один из концов канала егостандартным входным или выходным потоком. В этом случае на помощь приходитфункция dup2(), которая делает один файловый дескриптор равный другому. Вот какможно связать стандартный входной поток с файлом fd:
dup2 (fd, STDIN_FILENO);
Символическая константа STDIN_FILENO представляет дескриптор файла,соответствующий стандартному потоку ввода (значение этого дескриптора равно 0).Показанная функция закрывает входной поток, а потом открывает его подвидом файла fd. Оба дескриптора (0 и fd) будут указывать на одну и ту же позицию вфайле и иметь одинаковый набор флагов состояния, т.е. дескрипторы станутвзаимозаменяемые.
Программа представленная в листинге 2, с помощью функции dup2()соединяет выходной конец канала со входом команды sort. После создания каналапрограмма делиться функцией fork() на два процесса. Родительский процесссоединяет выходной конец канал со своим входным потоком, после чего запускаеткоманду sort.
Листинг №2:
/* dup2.c. Перенаправление выходного потока канала с помощью функцииdup2().*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h> #
int main ()
{
int fds[2];
pid_t pid; p
/*Создание канала. Дескрипторы обоих концов канала помещаются в массивfds*/ f
pipe (fds); p
/*Создание дочернего процесса*/ /
pid = fork ();
if (pid == (pid_t) 0)
{
/*Это дочерний процесс. Закрываем копию входного конца канала*/ /
close (fds[1]); ]
/*Соединяем выходной конец канала со стандартным входным потоком.*/ /
dup2 (fds[0], STDIN_FILENO); d
/*Замещаем дочерний процесс программой sort. *//
execlp ("sort", "sort", 0);
} }
else
{ {
/*Это родительский процесс.*/ /
FILE* stream; /*Закрываем копию выходного конца канала. */ /
close (fds[0]); ]
/*Приводим дескриптор входного конца канала к типу FILE* и записываемданные в канал.*/ д
stream = fdopen (fds[1], "w");
fprintf (stream, "Это тестовая программа.\n");
fprintf (stream, "Программу набрал (ФИО).\n");
fprintf (stream, "Из группы (номер). \n");
fprintf (stream, "Программа выводит строки по алфавитномупорядку.\n");
fprintf (stream, "Мы используем команду sort для сортировки.\n");
fprintf (stream, "Все строчки перепутались.\n");
fflush (stream);
close (fds[1]); c
/*Дожидаемся завершения дочернего процесса*/ /
waitpid (pid, NULL, 0);
}
return 0;
} }
Каналы часто используется для передачи данных программе, выполняющейся какподпроцесс или приема данных от нее. Специально для этих целей предназначеныфункции popen() и pclose(), устраняющие необходимость в вызове функции pipe(),dup2(), exec() и fdopen().
Использование данных функций рассмотрим в листинге 3:
Листинг 3.
/* popen.c . Использование функций popen() и pclose()*/
#include <stdio.h>
#include <unistd.h> #
int main ()
{
FILE* stream = popen ("sort", "w");
fprintf (stream, "Это тестовая программа.\n");
fprintf (stream, "Программу набрал (ФИО).\n");fprintf (stream, "Из группы (номер). \n");
fprintf (stream, "Программа выводит строки по алфавитному порядку.\n");
fprintf (stream, "Мы используем команду sort для сортировки.\n");
fprintf (stream, "Все строчки перепутались.\n");
fprintf (stream, "А эта программа короче предыдущей.\n");
return pclose (stream);
}
Функция popen() создает дочерний процесс, в котором выполняется команда sort.
Один этот вызов заменяет вызовы функций pipe(), fork(), dup2() и execlp().
Второй аргумент w , указывает на то что текущий процесс хочет осуществлять записьв дочерний процесс. Функция popen() возвращает указатель на один из концовканала; второй конец соединяется со стандартным входным потоком дочернегопроцесса. Функция pclose() закрывает входной поток дочернего процесса,дожидается его завершения и возвращает код статуса.
Первый аргумент функции popen() является командой интерпретатора,выполняемой в подпроцессе /bin/sh. Интерпретатор просматривает переменнуюсреды PATH, чтобы определить, где следует искать команду. Если второй аргументравен r , функция возвращает указатель на стандартный выходной поток дочернегопроцесса, чтобы программа могла читать данные из него. Если второй аргументравен w, функция возвращает указатель на стандартный входной поток дочернегопроцесса, чтобы программа могла записывать данные в него. В случае ошибкивозвращается пустой указатель.
Функция pclose() закрывает поток, указатель на который был возращен функциейpopen(), и дождаться завершения дочернего процесса.
Каналы FIFO
Файл FIFO (First-In, First-Out — первым пришел, первым обслужен) — этоканал, у которого есть имя в файловой системе. Любой процесс может открыть и закрыть такой файл.
Процессы, находящиеся на противоположных концах канала, не обязаны бытьсвязанными друг с другом. FIFO-файлы называются именованными каналами.
FIFO-файл создается с помощью команды mkfifo. Путь к файлу указывается вкомандной строке, например:
%mkfifo /tmp/fifo
Теперь в одном терминальном окне можно осуществлять чтение из файла спомощью команды
%cat < /tmp/fifo
, а в другом окне можно выполнять запись в файл.
%cat > /tmp/fifo
Попробуйте во втором окне ввести какой-нибудь текст, он тут же отобразиться впервом.
Удаляется FIFO-файл при помощи команды%rm -f /tmp/fifo
Создать FIFO-файл можно программным путем с помощью функции mkfifo().Первым аргументом является путь к файлу, второй аргумент задает права доступа кканалу.
Если канал не может быть создан — возвращается -1. Для работы с функцией необходимо подключить к программе заголовочные файлы <sys/types.h> и<sys/stat.h>.
Порядок выполнения работы
1. Прочитать методический материал;
2. Выучить понятия;
3. Набрать текст и скомпилировать программы, проверить работоспособность;
4. Проверить работоспособность fifo-каналов.
Скачать Операционные системы operacionnye-sistemy.zip [84,91 Kb] (cкачиваний: 37)

Информация

Комментировать статьи на нашем сайте возможно только в течении 60 дней со дня публикации.

Популярные новости

Статистика сайта



Rambler's Top100



 
Copyright © НеОфициальный сайт факультета ЭиП