ФЕДЕРАЛЬНОЕ АГЕНТСТВО СВЯЗИ
ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ОБРАЗОВАНИЯ
«САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ТЕЛЕКОММУНИКАЦИЙ ИМ. ПРОФ. М.А. БОНЧ-БРУЕВИЧА»
(СПбГУТ)
Кафедра программной инженерии и вычислительной техники
Отчёт
по лабораторной работе №7 на тему: «Разработка приложений под Linux»
по дисциплине «Операционные системы»
Выполнил: студент группы ИКВТ-61, UКозырев А.Б.
« » 2018 г. ___________/А.Б. Козырев/
Принял: __к.т.н. Дагаев А.В.
« » 2018 г. ___________/_А.В. Дагаев/
Задание: разработать приложение, использующее несколько процессов и объекты синхронизации под Linux.
Объект синхронизации: pipe
Исходный код
//пример 1
#include<stdio.h>
#include<unistd.h>
int main() {
int pipefds[2];
int returnstatus;
int pid;
char writemessages[2][20]={"Hi", "Hello"};
char readmessage[20];
returnstatus = pipe(pipefds);
if (returnstatus == -1) {
printf("Unable to create pipe\n");
return 1;
}
pid = fork();
if (pid == 0) {
read(pipefds[0], readmessage, sizeof(readmessage));
printf("Child Process - Reading from pipe – Message 1 is %s\n", readmessage);
read(pipefds[0], readmessage, sizeof(readmessage));
printf("Child Process - Reading from pipe – Message 2 is %s\n", readmessage);
} else {
printf("Parent Process - Writing to pipe - Message 1 is %s\n", writemessages[0]);
write(pipefds[1], writemessages[0], sizeof(writemessages[0]));
printf("Parent Process - Writing to pipe - Message 2 is %s\n", writemessages[1]);
write(pipefds[1], writemessages[1], sizeof(writemessages[1]));
usleep(1);
}
return 0;
}
Алгоритм
-
Шаг 1 - Создать pipe.
-
Шаг 2 - Создать дочерний процесс.
-
Шаг 3 - Родительский процесс пишет в pipe.
-
Шаг 4 - Дочерний процесс извлекает сообщение из pipe и записывает его в стандартный вывод.
-
Шаг 5 - Повторите шаг 3 и шаг 4 еще раз.
Результат работы программы:
В данной программе используется только один pipe для односторонней передачи данных, поэтому: либо родительский процесс записывает, либо дочерний процесс читает.
Покажем применение двухстороннего pipe для одновременной записи и чтения обоими процессами.
Исходный код
//пример 2
#include<stdio.h>
#include<unistd.h>
int main() {
int pipefds1[2], pipefds2[2];
int returnstatus1, returnstatus2;
int pid;
char pipe1writemessage[20] = "Hi";
char pipe2writemessage[20] = "Hello";
char readmessage[20];
returnstatus1 = pipe(pipefds1);
if (returnstatus1 == -1) {
printf("Unable to create pipe 1 \n");
return 1;
}
returnstatus2 = pipe(pipefds2);
if (returnstatus2 == -1) {
printf("Unable to create pipe 2 \n");
return 1;
}
pid = fork();
if (pid != 0) {
close(pipefds1[0]);
close(pipefds2[1]);
printf("In Parent: Writing to pipe 1 – Message is %s\n", pipe1writemessage);
write(pipefds1[1], pipe1writemessage, sizeof(pipe1writemessage));
read(pipefds2[0], readmessage, sizeof(readmessage));
printf("In Parent: Reading from pipe 2 – Message is %s\n", readmessage);
} else {
close(pipefds1[1]);
close(pipefds2[0]);
read(pipefds1[0], readmessage, sizeof(readmessage));
printf("In Child: Reading from pipe 1 – Message is %s\n", readmessage);
printf("In Child: Writing to pipe 2 – Message is %s\n", pipe2writemessage);
write(pipefds2[1], pipe2writemessage, sizeof(pipe2writemessage));
}
return 0;
}
Алгоритм
-
Шаг 1 – Создать два pipe. Сначала родитель должен писать, а ребенок читать, скажем, через pipe1. Во-вторых, ребенок должен писать, а родитель - читать, скажем, через pipe2.
-
Шаг 2 - Создать дочерний процесс.
-
Шаг 3 - Закрыть нежелательные концы, так как для каждого сеанса связи необходим только один конец.
-
Шаг 4 - Закрыть нежелательные концы в родительском процессе, конец для чтения в pipe1и конец для записи в pipe2.
-
Шаг 5 - Закрыть нежелательные концы в дочернем процессе, конец для чтения в pipe1 конец для записи в pipe2.
-
Шаг 6 - Выполнить сообщение процессов как требуется.
Наиболее точно данное действо иллюстрирует следующая обобщённая схема:
Результат работы программы:
Сначала родительский процесс записывает сообщение в первый pipe, затем он ожидает чтения сообщения, которое должен записать дочерний процесс. А дочерний процесс сначала считывает сообщение родителя “Hi” из конца read (pipefds1[0]), затем записывает своё сообщение в конец write (pipefds2[1]); когда родительский процесс обнаруживает в файловом дескрипторе pipefds2[0] запись, тотчас же выводит её в стандартный поток.
Итак: pipe file descriptors – вектор дескрипторов. pipefds1[0] – чтение, pipefds1[1] – запись. Родитель записывает только в pipefds1[1]. Ребёнок читает только из pipefds1[0].
pipefds2[0] – чтение, pipefds2[1] – запись. Ребёнок записывает только в pipefds2[1]. Родитель читает только из pipefds2[0].
Системный вызов функции pipe() заставляет операционную систему Linux инициализировать pipepfsX дескриптором из таблицы сигнальных переменный процесса, например 3 и 4, причём тех, которые не используются.
Выводы:
В результате мы достигли следующего:
-
Научились работать с процессами в системе Linux, также применили знания для написания программы;
-
Повторили материал по потокам ввода-вывода, стандартным конструкциям языка C++;
-
Использовали pipe в для взаимодействия процессов через системный вызов ОС Linux.
САНКТ-ПЕТЕРБУРГ 2018