Лабы, Разумовский / 3_laba / ООПЛинукс_3л
.docx
МИНОБРНАУКИ РОССИИ
Санкт-Петербургский государственный
электротехнический университет
«ЛЭТИ» им. В.И. Ульянова (Ленина)
Кафедра ВТ
отчет
по лабораторной работе №3
по дисциплине «Организация процессов и программирование в среде Linux»
Тема: Создание и идентификация процессов
Студент гр. |
|
|
Преподаватель |
|
Разумовский Г.В. |
Санкт-Петербург
2026
Цель работы
Изучение и использование системных функций, обеспечивающих порождение и идентификацию процессов
Задание
Разработать программу, которая порождает 2 потомка. Первый потомок порождается с помощью fork, второй - с помощью vfork с последующей заменой на другую программу. Все 3 процесса должны вывести в один файл свои атрибуты с предварительным указанием имён процесса. Имя выходного файла задаётся при запуске программы. Порядок вывода атрибутов в файл должен определяться задержками процессов, которые задаются в качестве параметров программы и выводятся в начало файла. Откомпилировать программу и запустить ее 3 раза с различными сочетаниями задержек.
Распечатка тестовой программы
own_prog.cpp
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstdlib>
using namespace std;
void writeAttributes(const char* procName, const char* filename, int delay) {
sleep(delay);
ofstream out(filename, ios::app);
out << "❤️❤️❤️❤️❤️ " << procName << " ❤️❤️❤️❤️❤️\n";
out << "Идентификатор процесса (PID): " << getpid() << "\n";
out << "Идентификатор предка (PPID): " << getppid() << "\n";
out << "Идентификатор сессии процесса (SID): " << getsid(0) << "\n";
out << "Идентификатор группы процессов (PGID): " << getpgid(0) << "\n";
out << "Реальный идентификатор пользователя (UID): " << getuid() << "\n";
out << "Эффективный идентификатор пользователя (EUID): " << geteuid() << "\n";
out << "Реальный групповой идентификатор (GID): " << getgid() << "\n";
out << "Эффективный групповой идентификатор (EGID): " << getegid() << "\n";
out << "+++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n";
out.close();
}
int main(int argc, char* argv[]) {
if (argc != 5) {
cerr << "Usage: " << argv[0] << " <file> <delay_parent> <delay_child1> <delay_child2>\n";
return 1;
}
const char* filename = argv[1];
int delayParent = atoi(argv[2]);
int delayChild1 = atoi(argv[3]);
int delayChild2 = atoi(argv[4]);
// Записываем параметры
ofstream out(filename);
out << "Параметры:\nЗадержка предка: " << delayParent << "\nЗадержка первого потомка: " << delayChild1 << "\nЗадержка второго потомка " << delayChild2 << "\n\n";
out.close();
// Первый потомок через fork
pid_t pid1 = fork();
if (pid1 == 0) {
writeAttributes("Первый потомок", filename, delayChild1);
exit(0);
}
// Второй потомок через vfork
pid_t pid2 = vfork();
if (pid2 == 0) {
// Заменяем на другую программу
execl("./child", "child", filename, argv[4], NULL);
_exit(1);
}
// Пишем атрибуты родителя
writeAttributes("Предок", filename, delayParent);
cout << "Done! Check " << filename << "\n";
return 0;
}
child.cpp
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <sys/types.h>
using namespace std;
int main(int argc, char* argv[]) {
if (argc != 3) return 1;
const char* filename = argv[1];
int delay = atoi(argv[2]);
sleep(delay);
ofstream out(filename, ios::app);
out << "❤️❤️❤️❤️❤️ Второй потомок ❤️❤️❤️❤️❤️\n";
out << "Идентификатор процесса (PID): " << getpid() << "\n";
out << "Идентификатор предка (PPID): " << getppid() << "\n";
out << "Идентификатор сессии процесса (SID): " << getsid(0) << "\n";
out << "Идентификатор группы процессов (PGID): " << getpgid(0) << "\n";
out << "Реальный идентификатор пользователя (UID): " << getuid() << "\n";
out << "Эффективный идентификатор пользователя (EUID): " << geteuid() << "\n";
out << "Реальный групповой идентификатор (GID): " << getgid() << "\n";
out << "Эффективный групповой идентификатор (EGID): " << getegid() << "\n";
out << "+++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n";
out.close();
return 0;
}
Результат выполнения программы с разными сочетаниями задержек
При сочетании задержек 1, 2, 3 секунды (предок, потомок 1, потомок 2 соответственно) первым завершает работу процесс-предок. В результате в выходной файл для обоих потомков записывается PID субрепера, а не исходного предка
При сочетании задержек 3, 2, 1 порядок завершения обратный: сначала 2 потомок, затем потомок 1, и в конце - предок. Поскольку на момент завершения потомков родитель всё ещё активен, в файл для них корректно записывается PID исходного предка.
При сочетании задержек 2, 1, 3 секунды потомок 1 завершается первым и успевает записать PID живого предка. Потом завершается сам предок, а потомок 2 к моменту завершения остаётся без предка, усыновляется субрепером и записывает его PID.
Рисунок 1 - Результат выполнения для сочетания задержек 1, 2, 3 секунд
Рисунок 2 - Результат выполнения для сочетания задержек 3, 2, 1 секунд
Рисунок 3 - Результат выполнения с сочетанием задержек 2, 1, 3 секунд
Вывод
В рамках лабораторной работы были рассмотрены механизмы создания процессов в ОС Linux, изучены их атрибуты и особенности взаимодействия в системе отношений «родитель -потомок».
Была реализована программа, создающая два дочерних процесса: первый - с помощью системного вызова fork(), второй - посредством vfork() с последующей заменой образа выполняемой программы через execl(). Все три процесса записывали свои атрибуты в общий текстовый файл, имя которого передавалось в качестве аргумента при запуске. Последовательность записи регулировалась временными задержками, также задаваемыми через параметры командной строки.
В ходе экспериментов было подтверждено, что порядок завершения процессов напрямую зависит от величины заданных задержек: процесс с наименьшей задержкой первым выполняет запись атрибутов и завершает работу. Выявлено, что при отсутствии вызова waitpid() родительский процесс не ожидает завершения дочерних, из-за чего при определённых комбинациях задержек потомки теряют родителя и передаются на обслуживание процессу -субреперу. Данный факт находит отражение в изменении значения, возвращаемого функцией getppid(): вместо PID исходного родителя потомки получают PID процесса -усыновителя.
Кроме того, установлено, что при усыновлении идентификаторы группы процессов (PGID) и сессии (SID) остаются неизменными: дочерние процессы сохраняют значения, унаследованные от исходного родителя, на всём протяжении своего существования.
