русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Лабораторная работа №9


Дата добавления: 2014-11-28; просмотров: 761; Нарушение авторских прав


Тема:Взаимодействие процессов. Именованные и неименованные программные каналы. Очереди сообщений. Семафоры. Разделяемая память.

Цель: Изучить методы взаимодействия процессов в системе UNIX.

 

Порядок выполнения работы:

  1. Выучить основные функции взаимодействия процессов.
  2. Написать и отладить программы, создающие процессы. Отработать их взаимодействие.
  3. Проанализировать результаты и сделать вывод.

 

Теоретические сведения:

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

В UNIX существует 4 основные средства связи между процессами:

  • Сигналы.
  • Именованные и неименованные каналы.
  • Очереди сообщений.
  • Разделяемая память.

Синхронизация процессов может осуществляться с помощью семафоров.

 

Неименованые каналы

PIPE

pipe - создает канал

 

СИНТАКСИС

#include <unistd.h>

int pipe(int filedes[2]);

 

ОПИСАНИЕ

pipe создает два файловых описателя, указывающих на именованный канал, и помещает их в массив filedes. filedes[0] предназначен для чтения, filedes[1] - для записи.

 

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При удачном завершении вызова возвращаемое значение равно нулю. При ошибке оно равно -1, а переменной errno присваивается номер ошибки.

 

DUP

dup, dup2 - функции, создающие копию описателя файла

 

СИНТАКСИС

#include <unistd.h>

int dup(int oldfd);

int dup2(int oldfd, int newfd);

 

ОПИСАНИЕ

dup и dup2 создают копию файлового описателя oldfd. После успешного вызова функции dup или dup2 старый описатель можно использовать вместо нового и наоборот. Они совместно блокируют файл, используют указатели позиции файла и флаги. Например, если позиция файла изменяется с помощью lseek в одном из описателей, то она изменяется также и в другом. Однако, два описателя имеют свой собственный флаг "close-on-exec". dup предоставляет новому описателю наименьший свободный номер. dup2 делает newfd копией oldfd, закрывая newfd, если это необходимо.



 

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

dup и dup2 возвращают новый описатель или значение -1, если произошла ошибка (в этом случае переменной errno присваивается значение соответствующего кода ошибки).

 

EXEC

execl, execlp, execle, execv, execvp - выполняют файл

 

СИНТАКСИС

#include <unistd.h>

extern char **environ;

int execl(const char *path, const char *arg,…);

int execlp(const char *file, const char *arg,…);

int execle(const char *path, const char *arg ,…,char * const envp[]);

int execv(const char *path, char *const argv[]);

int execvp(const char *file, char *const argv[]);

 

ОПИСАНИЕ

Семейство функций exec заменяет текущий образ процесса новым образом процесса. Начальным параметром этих функций будет являться полное имя файла, который необходимо исполнить.

Параметр const char *arg и аналогичные записи в функциях execl, execlp, и execle подразумевают параметры arg0, arg1, ..., argn. Все вместе они описывают один или нескольких указателей на строки, заканчивающиеся NULL, которые представляют собой список параметров, доступных исполняемой программе. Первый параметр, по соглашению, должен указывать на имя, ассоциированное с файлом, который надо исполнить. Список параметров должен заканчиваться NULL.

Функции execv и execvp предоставляют процессу массив указателей на строки, заканчивающиеся NULL. Эти строки являются списком параметров, доступных новой программе. Первый аргумент, по соглашению, должен указать на имя, ассоциированное с файлом, который необходимо исполнить. Массив указателей должен заканчиваться NULL.

Функция execle также определяет окружение исполняемого процесса, помещая после указателя NULL, заканчивающего список параметров (или после указателя на массив), argv дополнительного параметра. Этот дополнительный параметр является массивом указателей на строки, завершаемые NULL, и должен заканчиваться указателем NULL. Другие функции извлекают окружение нового образа процесса из внешней переменной environ текущего процесса.

Некоторые из этих функций имеют особую семантику.

Функции execlp и execvp дублируют действия оболочки, относящиеся к поиску исполняемого файла, если указанное имя файла не содержит символ черты (/). Путь поиска определяется в окружении переменной PATH . Если эта переменная не определена, то используется путь поиска ":/bin:/usr/bin" по умолчанию. Дополнительно обрабатываются некоторые ошибки.

Если запрещен доступ к файлу (при попытке исполнения execve была возвращена ошибка EACCES), то эти функции будут продолжать поиск вдоль оставшегося пути. Если не найдено больше никаких файлов, то по возвращении они установят значение глобальной переменной errno равным EACCES.

Если заголовок файла не распознается (при попытке выполнения функции execve была возвращена ошибка ENOEXEC), то эти функции запустят оболочку (shell) с полным именем файла в качестве первого параметра. (Если и эта попытка будет неудачна, то дальнейший поиск не производится.)

 

ВОЗВРАЩАЕМЫЕ ЗНАЧЕНИЯ

Возвращение значения какой-либо из функций exec приведет к ошибке. При этом возвращаемым значением будет -1 и глобальной переменной errno будет присвоен код соответствующей ошибки.

 

 

Пример программы

 

Данная программа запускает вторую программу (count.out) и передаёт ей данные для подсчёта по неименованному каналу. Та в свою очередь по второму каналу передаёт превой программе результат.

С помощью манипуляций с дескрипторами потоков достигается такая структура

 

Текст программы:

 

#include <stdio.h>

#include <unistd.h>

 

#define r 0 //конец канала для чтения

#define w 1 //конец канала для записи

 

int fd; //дескриптор файла с данными

int pid; //идентификатор процесса

int p[2],q[2]; //массивы дескрипторов для каналов

int total; //общее кол-во символов

char buff[1]; //буфер для чтения и записи

int n; //количество прочитанных байт

FILE *fp; //поток fp

 

int main(void)

{

pipe(p); //создаём канал с дескриптором р

pipe(q); //создаём канал с дескриптором q

pid=fork(); //порождаем процесс

switch(pid)

{

case -1:{perror("\n\tError in fork()");

return 0;} //если произошла ошибка - выходим

case 0:{ //находимся в дочернем процессе

close(p[w]); //закрываем конец канала р[1](для записи)

close(r); //закрываем стандартный поток 0 (ввод)

dup(p[r]); //дублируем конец р[0](чтение) на стандартный ввод

close(p[r]); //закрываем конец канала р[0]

close(q[r]); //закрываем конец канала q[0]

close(w); //закрываем стандартный поток 1 (вывод)

dup(q[w]); //дублируем конец q[1](запись) на стандартный вывод

close(q[w]); //закрываем конец канала q[1]

if((execl("count.out","count.out",0))==-1) //запускаем прог-

perror("\n\tError in execl()"); //раму подсчёта символов

return 0;

}

default:{ //находимся в родительском процессе

close(p[r]); //закрываем конец канала р[0] (чтение)

close(q[w]); //закрываем конец канала q[1] (запись)

fp=fdopen(p[w],"w"); //открываем поток канала p[1](запись)

if((fd=open("data.txt",0))<0) //открываем файл с данными

{perror("\n\tError in open()");return 0;}

while((n=read(fd,buff,sizeof(buff))>0)&&(buff[0]!=EOF))

{ //читаем из файла символы пока не дойдём до конца файла

putc(buff[0],fp); //записываем символ в конец канала p[1]

printf(" buff=%c ",buff[0]); //выводим символ на экран

}

fclose(fp); //закрываем поток конца канала p[1]

close(r); //закрываем стандартный ввод

dup(q[r]);//дублируем канала q[0](чтение) на стандартный ввод

close(q[r]); //закрываем конец канала q[0]

scanf("%d",&total); //читаем со ст. ввода количество символов

printf("\n\tTotal number of symbols : %d \n",total);//выводим

} //его на экран

}

return 0;

}

 

Файл count.c

 

#include <stdio.h>

int count=0;

int main(void)

{

while(getchar()!=EOF) count++;

printf("%d\n",count);

return 0;

}

 

 



<== предыдущая лекция | следующая лекция ==>
SIGACTION | Именованные каналы


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.503 сек.