- •Содержание
- •1. Теоретическая часть
- •1.1 Процессы. Создание процессов – функция fork()
- •1.2 Передача управления: execve()
- •1.3 Семейство exec().
- •1.4 Ожидание процесса wait().
- •1.5 Межпроцессорное взаимодействие, каналы( pipe() ).
- •2. Описание базовых программ
- •3. Список заданий
- •I. К части 1 (программа 2.1)
- •II . По части номер 2(программа 2)
- •III. По части номер 3(программа 3)
- •Список использованной литературы.
Содержание
1. Теоретическая часть 2
1.1 Процессы. Создание процессов – функция fork() 2
1.2 Передача управления: execve() 5
1.3 Семейство exec(). 7
1.4 Ожидание процесса wait(). 8
1.5 Межпроцессорное взаимодействие, каналы( pipe() ). 10
2. Описание базовых программ 14
3. Список заданий 19
4. Список использованной литературы. 20
1. Теоретическая часть
1.1 Процессы. Создание процессов – функция fork()
Термин "процесс" впервые появился при разработке операционной системы Multics и имеет несколько определений, которые используются в зависимости от контекста. Процесс - это:
1) программа на стадии выполнения.
2) "объект", которому выделено процессорное время.
3) программа + системные данные.
Для описания состояний процессов используется несколько моделей. Самая простая модель - это модель трех состояний. Модель состоит из:
1) состояния выполнения
2) состояния ожидания
3) состояния готовности
Выполнение - это активное состояние, во время которого процесс обладает всеми необходимыми ему ресурсами. В этом состоянии процесс непосредственно выполняется процессором.
Ожидание - это пассивное состояние, во время которого процесс заблокирован, он не может быть выполнен, потому что ожидает какое-то событие, например, ввода данных или освобождения нужного ему устройства.
Готовность - это тоже пассивное состояние, процесс тоже заблокирован, но в отличие от состояния ожидания, он заблокирован не по внутренним причинам (ведь ожидание ввода данных - это внутренняя, "личная" проблема процесса - он может ведь и не ожидать ввода данных и свободно выполняться - никто ему не мешает), а по внешним, независящим от процесса, причинам.
Над процессами можно производить следующие операции:
1) Создания
2) Уничтожения
4) Изменения приоритет
5) Блокирования
6) Пробуждения
7) Запуск процесса (или его выбор)
Для создания процесса операционной системе нужно:
1) Присвоить процессу имя и номер
2) Добавить информацию о процессе в системную таблицу процессов
3) Определить приоритет процесса
4) Предоставить процессу нужные ему ресурсы
Каждому процессу в системе назначаются числовые идентификаторы (личные номера) в диапазоне от 1 до 65535 (PID – Process Identifier – идентификатор процесса) и идентификаторы родительского процесса (PPID – Parent Process Identifier – идентификатор родительского процесса). PID является именем процесса, по которому он адресуется в операционной системе. PID каждого процесса уникальный, т.е. не может быть два запущенных процесса , имеющих один и тот же PID. Зачастую PID возрастают в значениях, т.е. PID порожденного процесса обычно имеет большее значения чем PID его родителя, но в случае переполнения, порожденный процесс создается с любым меньшим не используемым номером PID. PPID определяет родственные отношения между процессами, которые в значительной степени определяют его свойства и возможности.Если родительский процесс завершается, порожденному процессу в качестве родителя назначается родитель родителя. Если процесса верхнего уровня нет, то в качестве родителя назначается системный процесс init, PID которого равен 1.
Для порождения нового процесса предназначен системный вызов fork(), объявленный в заголовочном файле unistd.h следующим образом:
pid_t fork(void);
Системный вызов fork() порождает процесс методом “клонирования”. Это значит, что новый процесс является точной копией своего родителя и выполняет ту же самую программу.
Листинг 1.1 fork1.c
#include <unistd.h>
#include <stdio.h>
int main(void)
{
fork();
printf(“Helo World!\n”);
sleep(20);
return 0;
}
В результате мы получим, что фраза “Hello World!” напечаталась 2 раза. Это объясняется тем, что каждый процесс продолжил самостоятельно выполнять одну и туже программу.
Чтобы в контексте программы отделить один процесс от другого, достаточно знать, что системный вызов fork(), возвращает в текущем процессе PID порожденного потомка (или -1 в случае ошибки). А новый процесс возвращает 0.
Листинг 1.2 fork2.c
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
int main(void)
{
pid_t result = fork();
if (result == -1)
{
fprintf(strerr,”Error\n”);
return 1;
}
if (result == 0)
printf(“I’m child whit PID = %d\n”,getpid());
else
printf(“I’m parent whit PID = %d\n”,getpid());
return 0;
}
Системный вызов getppid() возвращает PID родителя, а системный вызов getpid() – PID текущего процесса, оба системных вызова определены в <unistd.h>. Обработка ошибок с помощью библиотечной функции stderr() из модуля <errno.h>, получение номеров родителя и потомка представлены в листинге 2.1.
Листинг 1.3 getpid.c.
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char** argv)
{
pid_t pid_number, child, parent;
printf("\nOriginal parent: %d\n", getpid());/*перед fork()*/
if ((pid_number = fork()) < 0)
{
fprintf(stderr,"%s: fork of child failed: %s\n", argv[0],strerror(errno));
exit(1);
}
else if (pid_number == 0 )
{
child = getpid();
parent = getppid();
printf("Child: my PID%d my PPID= %d \n ",child, parent);
}
else {
printf("Parent: my PID = %d my PPID = %d \n", getpid(), getppid());
printf("Parent: my child process PID = %d \n ", pid_number);
exit(0);/*родитель завершается после fork()*/
}
/*нижележащий код выполняет только порожденный процесс*/
….
exit(0);
}
После завершения функции fork() в ОС присутствуют уже два одинаковых процесса, различающихся только своими PID и PPID.