Классические межпроцессные коммуникации



В классических версиях системы UNIX процессы могут взаимодействовать, используя программные каналы и аппарат сигналов, составляющие классический аппарат InterPprocess Communications (IPC).

Программный канал представляет собой очередь в адресном пространстве ядра системы, через которую процессы могут обмениваться данными. Для доступа в этот канал используют два файловых дескриптора, возвращаемые системным вызовом pipe. Один из этих дескрипторов используется для записи в канал, другой – для чтения из него. Программный канал обычно является однонаправленным, и для двухстороннего обмена данными необходимо создавать два программных канала. Подобное средство применимо для связи между процессами–родственниками, поскольку только в этом случае обеспечивается наследование дескрипторов точек входа в программный канал.

Общепринятый метод создания программного канала:

Вызывается pipe для создания файловых дескрипторов.

С помощью fork порождаются процессы-потомки, наследующие дескрипторы.

Порожденные процессы обмениваются данными через канал, используя обычный файловый API.

Пример простейшей программы, использующей подобный обмен, приведен ниже.

Листинг progpipe.c

 

#include <stdio.h>

int pipe1[2];

char cbuf[80];

int i, j, err, n;

int fd;

main(void)

{

if ((err=pipe(pipe1)<0)) { //Create pipe

     perror ("Error creating pipe");

     exit();

}

if (fork()) //Create new process

{     //Parent process

if ((fd=open("progpipe.c",0))<0) {

      perror("Open file error");

      exit();

}

while ((n=read(fd,cbuf,80))>0)  //rewrite file

write(pipe[1],cbuf,n);

close(fd); //close pipe for write

close(pipe1[1]);

wait();

exit();

}

else //Child process

{

close(0);

fd=dup(pipe1[0]);

close(pipe1[0]);

close(pipe1[1]);

execl ("/bin/cat","cat",0);

perror("Cat error");

}

 

В программе запускаются два процесса, один из которых читает текст программы и по программному каналу передает его второму процессу, который, в свою очередь, запускает для отображения этих данных команду cat. Используется техника замены файловых дескрипторов, в результате которой cat читает свой стандартный ввод.

Сигналы инициируются событиями и посылаются процессу для уведомления о том, что это событие произошло. Сигналы различаются своими номерами – целыми числами, начиная с 1. В файле <signal.h> определены символические имена сигналов, символические имена реакции на них, используемые типы данных и описания системных вызовов.

Для каждого сигнала процесс должен иметь реакцию – некоторое действие. Реакция на сигналы может быть следующая:

SIG_DFL - стандартная реакция системы,

SIG_IGN - игнорирование,

<указатель на функцию> - при поступлении сигнала выполняется указанная функция.

Все реализации поддерживают следующие стандартные (POSIX) сигналы, сведенные в табл. 6.

 

Таблица 6.

Стандартные сигналы

 

Имя сигнала Ситуация, в которой генерируется сигнал Реакция по умолчанию
SIGABRT Аварийное завершение. Генерируется, в частности, вызовом abort Завершение + core
SIGALRM Таймер процесса. Генерируется, в частности, вызовом abort Завершение
SIGFPE Недопустимая арифметическая операция Завершение + core
SIGHUP Разрыв связи с терминалом Завершение
SIGILL Недопустимая машинная команда Завершение
SIGINT Терминальное прерывание. Обычно генерируется клавишами Ctrl/C Завершение
SIGKILL Безусловное завершение процесса. Генерируется, в частности, командой kill -9 <PID> Завершение
SIGQUIT Терминальное завершение. Обычно генерируется клавишами Ctrl/\ Завершение
SIGSEGV Нарушение защиты памяти. Генерируется, в частности, при разыменовании указателя со значением NULL Завершение + core
SIGTERM Завершение процесса. Генерируется, в частности, командой kill <PID> Завершение
SIGUSR1 Зарезервировано для программ пользователя Завершениe
SIGUSR2 Зарезервировано для программ пользователя Завершение
SIGCHLD Завершение порожденного процесса Игнорирование
SIGCONT Возобновление остановленного процесса Возобновление процесса
SIGSTOP Остановка процесса Остановка
SIGTTIN Попытка фонового процесса читать с управляющего терминала Остановка
SIGTTOU Попытка фонового процесса записывать на управляющий терминал Остановка
SIGTSTP Терминальная остановка процесса. Генерируется, в частности, при нажатии клавиши Ctrl/Z Остановка

 

При обработке некоторых сигналов в текущем каталоге создается файл core, содержащий образ памяти (дамп) процесса. Сигналы SIGSTOP и SIGKILL не могут быть перехвачены и игнорированы.

Сигнал может быть блокирован от передачи процессу. Каждый процесс имеет сигнальную маску, определяющую множество блокированных сигналов. Эта маска наследуется при порождении нового процесса.

Программным путем сигнал может быть сгенерирован при помощи функции kill:

int kill (pid_t pid, int signal_num)

 Параметрами задается номер сигнала и идентификатор процесса, которому посылается сигнал. В зависимости от этого идентификатора сигнал посылается определенному процессу либо группе процессов, что поясняет табл. 7.

 

Таблица 7.

Определение процессов, которым посылается сигнал

 

Значение pid Процесс, которому посылается сигнал
pid > 0 Процесс с PID=pid
pid=0 Все процессы группы (с одинаковыми GID)
pid=-1 Все процессы владельца (с реальным UID, совпадающим с EUID вызывающего процесса)
pid < 0 Группа процесов (процессы с GID=abs(pid))

 

Реакция на сигналы в классической UNIX определяется с помощью системного вызова signal, которому задаются номер сигнала и реакция на него (указатель на функцию-обработчик сигнала):

void (*signal (int signal_num, void (*handler) (int))))(int)

 Вызов возвращает указатель на старый обработчик данного сигнала. При перехвате сигнала ядро вначале деактивирует обработчик, а затем вызывает обрабатывающую сигнал функцию. Таким образом, при посылке нескольких экземпляров сигнала перехватывается только первый, все же остальные обрабатываются методом, принятым по умолчанию. Для непрерывного перехвата множества сигналов требуется реинсталлировать функцию-обработчик при каждом перехвате (вызывать signal из обработчика), хотя полной гарантии перехвата всех экземпляров сигнала такой метод все же не дает.

Функция-обработчик не возвращает никакого значения и должна иметь один целочисленный аргумент - номер сигнала.

Пример программы, обрабатывающей нажатие клавиши Ctrl/C (сигнал SIGINT):

Листинг signal.c

#include <signal.h>

#include <stdio.h>

FILE *fildes;

int c;

int sig;

static void myint (int sig)

{

char cl;

signal(SIGINT, myint);

printf ("\nSignal # %d\n Continue? ",sig);

cl = getchar ();

if (cl != 'y') exit (1);

}

void main (argc,argv)

char **argv;

int argc;

{

int k;

long i;

 

setvbuf(stdin, NULL, _IONBF, 0);

setvbuf(stdout, NULL, _IONBF, 0);

 

signal (SIGINT, myint);

 

argc--;

argv++;

while(argc--) {

if ((fildes = fopen(*argv++, "r")) == NULL) {

      perror ("Open file"); exit(-1);

}

while ((c=getc(fildes)) != EOF) {

      putchar(c);

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

}       

fclose (fildes);

}

}

Программа распечатывает содержимое файлов, указываемых в качестве аргументов. При нажатии клавиши Ctrl/C управление передается функции myint, вновь устанавливающей обработчик, распечатывающей номер перехватываемого сигнала и запрашивающей дальнейшие действия. Если не вводится признак продолжения распечатки, выполнение программы заканчивается. Для корректной работы программы отменяется буферизация стандартных файлов с помощью системного вызова setvbuf. Чтобы замедлить распечатку, вводится цикл активного ожидания (цикл for).

Рассмотренный механизм обработки сигналов считается устаревшим и ненадежным. В современных версиях UNIX в качестве альтернативного соответствующего стандарту POSIX интерфейса используется другой набор функций. При этом остается доступным старый механизм обработки с использованием функции signal.

Для задания сигнальных масок, определяющих, какие из посылаемых процессу сигналов блокируются, вводится понятие множества сигналов (signal set), описываемого переменной типа sigset_t. Каждый бит этой переменной отвечает за один сигнал. Обычно этому типу соответствует тип unsigned long длиной 32 бита, при этом число возможных сигналов ограничено числом 32.

Для манипулирования множествами сигналов определены функции, сведенные в табл. 8.

Таблица 8.

Функции, работающие с множествами сигналов

Функция Описание
int sigemptyset(sigset_t *set) Инициализация пустого множества сигналов set (все его биты обнуляются); из него исключаются все определенные в системе сигналы
int sigfillset(sigset_t *set) Инициализация полного множества сигналов set (все его биты устанавливаются в 1), включающего все определенные в системе сигналы
int sigaddset(sigset_t *set, int signo) Добавление сигнала signo к множеству set
int sigdelset(sigset_t *set, int signo) Удаление сигнала signo из множества set
int sigismember(sigset_t *set, int signo) Проверка принадлежности сигнала signo множеству set

Параметр new_mask определяет новую, а old_mask – возвращает старую сигнальные маски. Параметр cmd определяет варианты использования аргумента new_mask, как показано в табл. 9.

 

Таблица 9.

Действия с сигнальной маской

 

Значение cmd Выполняемые действия
SIG_SETMASK Замена сигнальной маски процесса значением new_mask
SIG_BLOCK В сигнальную маску процесса добавляются сигналы из множества new_mask
SIG_UNBLOCK Из сигнальной маски процесса удаляются сигналы, указанные в множестве new_mask

 

Вместо функции signal вводится функция sigaction:

int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)

Задается номер обрабатываемого сигнала, аргументом act определяются новые действия по обработке сигнала и возвращается в параметре oact старый метод обработки. Вся необходимая для управления сигналами информация передается через структуру типа sigaction. Такая структура имеет поля, перечисленные в табл. 10.

 

Таблица 10.

Структура sigaction

 

Поле Описание
void (*sa_handler)(int) Обработчик сигнала sig
sigset_t sa_mask Множество сигналов, которые дополнительно блокируются на время обработки сигнала sig
int sa_flag Опция, задающая специальные методы обработки некоторых сигналов

 

При генерации нескольких экземпляров сигналов все они обрабатываются одинаково. Таким образом, использование sigaction позволяет получить дополнительную функциональность обработки и обеспечивает надежную доставку сигналов.

Программа, выполняющая те же действия, что и в предыдущем примере, но использующая современный механизм обработки сигналов, приведена ниже.

 

Листинг sigactiondemo.c

#include <signal.h>

#include <stdio.h>

FILE *fildes;

int c;

int sig;

static  void  myint  (int  sig)

{

char  cl;

printf ("\nSignal  # %d\n  Continue? ", sig);

cl = getchar ();

if  (cl == 'n') exit (1);

}

void main (argc, argv)

char  **argv;

int argc;

{

int  k;

long  i;

struct  sigaction  action,  old_action;

setvbuf(stdin,  NULL,  _IONBF, 0);

setvbuf(stdout,  NULL,  _IONBF, 0);

action.sa_handler=myint;

sigemptyset(&action.sa_mask);

if ((k=sigaction (SIGINT, &action, &old_action))  < 0)

{

     perror("sigaction");

     exit();

}

argc--;

argv++;

while(argc--)  {

     if  ((fildes = fopen(*argv++,  "r")) == NULL)  {

      perror ("Open file"); exit(1);

}

while  ((c=getc(fildes)) != EOF) {

      putchar(c);

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

}       

fclose (fildes);

}

}

ЛАБОРАТОРНЫЕ РАБОТЫ

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

Целью данной лабораторной работы является первоначальное знакомство с ОС UNIX. В процессе работы слушатели регистрируются в системе, осваивают оболочку Midnight Commander, рассматривают особенности файловой системы UNIX, выполняют основные команды UNIX. Затем слушатели осваивают особенности регистрации в системе удаленных пользователей и особенности работы с виртуальными терминалами.

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

Целью данной лабораторной работы является знакомство с программированием на языке Shell, используя интерпретатор команд bash. Для этого слушатели разрабатывают программы (сценарии) на этом языке, выполняя одно из следующих заданий:

Разработать программу, рассылающую 31 декабря всем пользователям поздравления с Новым годом.

Разработать программу, ведущую телефонный справочник.

Разработать программу, ведущую картотеку книг.

Разработать оболочку администратора, позволяющую:

форматировать дискетты;

выдавать информацию о работающих пользователях;

выдавать информацию о зарегистрированных пользователях;

выдавать информацию о пользователях, вошедших в систему по rlogin.

Разработать оболочку пользователя, позволяющую использовать систему меню.

Разработать программу, выдающую информацию о поддереве файловой системы: суммарный объем, рекурсивный список всех подкаталогов.

Разработать программу диалогового удаления файлов в поддереве файловой системы.

Разработать программу, анализирующую содержание каталога. Для всех объектов определяется их размер. Содержимое подкаталогов распечатывается, для файлов определяется их тип.

Разработать программу, моделирующую калькулятор (задаются выражения, используются 5 внутренних регистров).

Разработать программу, выдающую информацию о работающих пользователях: имя, группа, состав группы, домашний каталог, интерпретатор команд.

 

Лабораторные работы № 3,4.

 Целью данной работы является ознакомление с использованием стандартизованных системных вызовов, позволяющих управлять файлами и процессами. Рассматриваются также принципы взаимодействия процессов на базе классических механизмов межпроцессных коммуникаций (IPC). В процессе ее выполнения разрабатываются программы на языке C, использующие эти системные вызовы.

Системные вызовы управления файлами. Разрабатываются программа, позволяющая:

создать файл;

записать в него данные из другого файла;

изменить права доступа к этому файлу;

уничтожить файл.

Системные вызовы управления процессами. Разрабатывается программа, запускающая два процесса, которые сообщают свои параметры (как минимум, свои идентификаторы и идентификаторы родительских процессов). Для обеспечения возможности наблюдения за ними вводятся задержки их окончания. Прослеживается (командой ps и путем просмотра каталога /proc) их функционирование; путем уничтожения родительского процесса создается состояние «зомби».

Классические межпроцессные коммуникации:

на базе предыдущей разрабатывается программа, запускающая два процесса, которые обмениваются данными через программный канал;

разрабатывается программа, которая устанавливает реакцию на нажатие клавиши Ctrl/C ( cигнал INT) и обрабатывает это нажатие.

 

 

БИБЛИОГРАФИЧЕСКИЙ СПИСОК

Дунаев С. UNIX SYSTEM V. Release 4.2. Общее руководство. М.: "Диалог-МИФИ",1995. 287с.

Беляков М.И., Рабовер Ю.И., Фридман А.Л. Мобильная операционная система: Справочник. М.: Радио и связь, 1991. 208с.

Робачевский А.М. Операционная система UNIX. СПб.: BHV Санкт-Петербург, 1997. 528с.

Келли-Бутл С. Введение в UNIX: Пер с англ. М.:"Лори", 1995. 596с.

Петерсен Р. LINUX: Руководство по операционной системе: В 2 т. Пер. с англ. 2-е изд. К.: BHV, 1998. Т. 1 528с, Т. 2 480с.

Такет Дж., Гантер Д. Использование Linux: Пер с англ. 3-е изд. К.; М.; СПб: «Вильямс», 1998. 576с.

Чан Т. Системное программирование на С++ для UNIX: Пер. с англ. К.: BHV, 1997. 592с.

Соловьев А.Е.  Программирование на shell (UNIX):    Учебное пособие. 46с. http://www.citforum.ru/programming/shell/index.shtml


ОГЛАВЛЕНИЕ

ВВЕДЕНИЕ                                                                                      3

1. ФАЙЛОВАЯ СИСТЕМА UNIX                                                  4

2. ПРОГРАММИРОВАНИЕ НА ЯЗЫКЕ SHELL                        9

2.1. Простейшие средства shell                                                9

2.2. Элементы языка shell                                                        10

2.3. Параметры                                                                            10

2.4. Интерпретация слов                                                           12

2.5. Группировка команд.                                                          13

2.6. Операторы языка shell                                                      14

3. ПРОГРАММНЫЙ ИНТЕРФЕЙС СИСТЕМЫ UNIX            20

3.1. Базовый ввод/вывод                                                           20

3.2. Управление процессами                                                    23

3.3. Классические межпроцессные коммуникации              28

4. Лабораторные работы                                                 36

Лабораторная работа № 1                                                         36

Лабораторная работа № 2                                                         36

Лабораторные работы № 3,4.                                                   37

Библиографический список                                          38

 


Дата добавления: 2019-02-12; просмотров: 328; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!