- •Лабораторная работа по курсу "Операционные системы" Процессы в ос Linux (I)
- •Идентификаторы процессов
- •Просмотр активных процессов
- •Код завершения процесса
- •Создание процессов
- •Переключение процесса на выполнение другой программы
- •Совместный доступ к файлам родительского и дочернего процессов
- •Порядок выполнения лабораторной работы
- •Требования
- •Вопросы
- •Источники информации
Лабораторная работа по курсу "Операционные системы" Процессы в ос Linux (I)
Цель работы: знакомство с системными вызовами для создания процессов; исследование состояния гонок при совместном доступе к файлу родительского и дочернего процессов.
Идентификаторы процессов
Процессы в ОС Linux имеют уникальные номера - идентификаторы процессов (PID), являющиеся целыми числами, назначаемыми процессам при их создания. В программах, написанных на С/С++, предпочтительнее использовать для PID не тип int, а тип pid_t, описанный в файле <sys/types.h>.
Для получения программой PID собственного процесса используется системный вызов getpid, для получения PID родительского процесса - getppid.
Задание 1. Выполните программу pr1.c:
/* pr1.c */
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("PID is %d\n", getpid());
printf("PPID is %d\n", getppid());
return 0;
}
Выполните программу несколько раз. Запишите значения PID и PPID и объясните результаты в отчете.
Просмотр активных процессов
Для просмотра активных процессов предназначены следующие команды:
ps (Process Status). Введенная без опций, команда ps показывает только те процессы, которые были запущены из данного терминального окна.
top показывает активные процессы в динамике.
pstree показывает активные процессы в виде дерева.
Задание 2.
2.1. Введите команду $ps.
Занесите в отчет полученную информацию. Введите команду ps со следующими опциями:
$ps -e -o pid,ppid,start_time,command
$ps -f -A
$ps -l
$ps -la
Законспектируйте информацию об использованных Вами опциях команды ps. Определите, какой процесс является родителем процесса ps, и какой - родителем его родителя и т.д. Для последней команды расшифруйте значения колонок листинга.
2.2. Введите команду $top.
2.3. Введите команду $pstree.
Код завершения процесса
В нормальной ситуации процесс завершается либо системным вызовом exit либо возвратом из функции main. Код завершения - это двухбайтное целое число, возвращаемое процессом своему родителю. Это число - аргумент функции exit или значение, возвращаемое функцией main. Старший байт кода возврата равен коду возврата программы (так называемый пользовательский код возврата). В младший байт ОС записывает причину завершения процесса (системный код возврата; при нормальном завершении процесса он равен нулю).
Создание процессов
Способ 1. Использование system.
При помощи функции system из стандартной библиотеки языка С stdlib можно выполнить команду изнутри программы, как если бы эта команда выла введена в оболочке. Команда system возвращает код возврата команды оболочки. При неудачном запуске оболочки код возврата равен 127, если произошли другие ошибки, то код возврата равен -1.
Задание 3. Выполните программу pr3.c, в которой запускается команда "ls -l /":
/* pr3.c */
#include <stdio.h>
#include <stdlib.h>
int main()
{
int ret_val;
ret_val = system("ls -l /");
printf("Return code is %d\n", ret_val);
return ret_val;
}
Запишите в отчет код возврата функции system при успешном и неуспешном (задайте для ls несуществующий каталог) выполнении. Выведите код завершения программы pr3.c также и из оболочки, пользуясь соответствующей переменной оболочки (см. лабораторную работу 1).
Создание нового процесса при помощи system не следует использовать в программах, т.к. он может вести себя по-разному в разных версиях Linux.
Способ 2. Использование fork.
Основной способ создания процессов - системный вызов fork, который создает дочерний процесс, являющийся копией своего родительского процесса. При неудаче fork возвращает -1. При успешном выполнении fork возвращает 0 в созданный дочерний процесс и возвращает PID дочернего процесса в родительский процесс.
Задание 4.
4.1. Выполните следующую программу:
#include <stdio.h>
#include <unistd.h>
int main()
{
fork(); printf("A\n");
fork(); printf("B\n");
return 0;
}
Сколько процессов будет выполнено? Сколько сообщений будет напечатано? Нарисуйте дерево процессов. Почему приглашение оболочки $ появляется раньше, чем программа завершает работу?
4.2. Выполните программу pr4.c:
/* pr4.c */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t child_pid;
printf("The main program process ID is %d\n", getpid());
child_pid = fork();
if (child_pid !=0) {
printf ("This is the parent process, with ID %d\n", getpid());
printf ("the child's process ID is %d\n", child_pid);
}
else
printf ("This is the child process, with ID %d\n", getpid());
return 0;
}
а) Запишите в отчет выходные данные, выведенные программой.
б) Распечатайте в дочернем процессе PID его родителя и выполните программу. Модифицируйте программу: после fork задержите выполнение родительского процесса на 3 единицы времени (при помощи библиотечной функции sleep), а дочернего - на 10 единиц. Распечатайте в дочернем процессе PID его родителя дважды: до и после sleep. Объясните в отчете полученные результаты.
