Лабораторная работа №2
«Работа с процессами в ОС Linux»
Цели: Изучение создания, контроля и завершения процессов в ОС Linux.
Задачи: Знакомство с функциями ОС Linux для работы с процессами. Получение первоначальных навыков управления состояниями процессов.
Срок выполнения: 2 недели
Общие сведения
Процесс в Unix/Linux представляет собой единицу работы вычислительной системы, которой операционная система выделяет ресурсы. Каждый процесс в системе имеет свой уникальный идентификатор процесса (PID), представляемый целым числом. Существует так же идентификатор родительского процесса (PPID).
Процесс может порождать другой процесс. Порождение нового процесса в ОС Linux реализовано копированием записи таблицы процессов, таким образом, что дочерний процесс (процесспотомок) в момент своего порождения представляет собой точную копию родительского процесса (процесса-предка). Родительский процесс и дочерний процесс далее выполняются параллельно, но родительский процесс может и ожидать завершения дочернего процесса.
Новый процесс порождается системным вызовом fork(), который создает дочерний процесс - копию родительского. Прототип данной функции находится в <unistd.h>. В дочернем процессе выполняется та же программа, что и в родительском, и когда дочерний процесс начинает выполняться, он выполняется с точки возврата из системного вызова fork(). Системный вызов fork() возвращает родительскому процессу PID дочернего процесса, а дочернему процессу - 0. По коду возврата вызова fork() дочерний процесс может "осознать" себя как дочерний. Свой PID процесс может получить при помощи системного вызова getpid(), а PID родительского процесса - при помощи системного вызова getppid(). Если требуется, чтобы в дочернем процессе выполнялась программа, отличная от программы родительского процесса, процесс может сменить выполняемую в нем программу при помощи одного из системных вызовов семейства exec. Все вызовы этого семейства загружают для выполнения в процессе программу из заданного в вызове файла и отличаются друг от друга способом передачи параметров этой программе. Таким образом, наиболее распространенный контекст применения системного вызова fork() выглядит примерно так:
/* порождение дочернего процесса и запоминание его PID */ if (!(ch_pid=fork()))
/* загрузка другой программы в дочернем процессе */ exec(программа);
else /* продолжение родительского процесса */
Пример программы на языке С.
#include <stdio.h>
#include <unistd.h>/* contains fork prototype */ int main(void)
{ int pid;
printf("Hello World!\n");
printf("I am the parent process and my PID is : %d.\n",getpid()); printf("Here I am before use of forking\n"); pid = fork();
printf("Here I am just after forking\n"); if (pid == 0)
printf("I am the child process and PID is :%d.\n",getpid()); else
printf("I am the parent process and PID is: %d.\n",getpid()); return 0;
}
Примерный результат работы программы:
Hello World!
I am the parent process and my PID is : 23951.
Here I am before use of forking
Here I am just after forking
Here I am just after forking
I am the child process and my PID is :23952.
I am the parent process and my PID is: 23951.
Нормальное завершение процесса происходит при достижении конца функции main или при выполнении системного вызова exit(). При этом процесс устанавливает некоторый код своего завершения, который может быть прочитан процессом-предком. Существует общепринятое соглашение, по которому 0 означает нормальное завершение, а любое другое значение – ошибку или необычное происшествие. Множество стандартных библиотечных вызовов используют ошибки, определенные в <sys/stat.h>.
Принудительное завершение процесса извне может быть выполнено при помощи системного вызова kill(), посылающего процессу сигнал. С сигналами мы познакомимся при выполнении следующих лабораторных работ, пока же только отметим, что гарантированно "убить" процесс, имеющий PID = p, можно системным вызовом kill(p,SIGKILL).
Ожидание завершения процесса
Процесс-предок может ожидать завершения процесса-потомка (или процессов-потомков) при помощи системных вызовов wait() или waitpid(). Прототипы этих функций находятся в <sys/wait.h>. Если процесс-потомок еще не завершился, процесс-предок переводится таким системным вызовом в состояние ожидания до завершения процесса-потомка (впрочем, процесс может и не ожидать завершения потомка, а только проверить, завершился ли он). Эти системные вызовы позволяют также процессу предку узнать код завершения потомка.
Пример программы.
#include <stdio.h>
#include <sys/wait.h> /* contains prototype for wait */ int main(void)
{ int pid; int status;
printf("Hello World!\n"); pid = fork( ); if (pid == -1)
{
perror("bad fork"); exit(1); } if (pid == 0)
printf("\t I am the child process.\n"); else {
wait(&status); /* parent waits for child to finish */ printf("I am the parent process.\n");
} return 0;
}
Результат работы программы:
Hello World!
I am the child process.
I am the parent process.
Задания на лабораторную работу:
1. Изучите команды ps и kill. Запустите любую свою программу, используя в конце & (например:
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.