Лабораторная работа 6 (дополнительная)
Процессы в ОС Linux
Теоретический материал
В ОС Linux для создания процессов используется системный вызов fork()
:
#include <sys/types.h>
#include <unistd.h>
pid_t fork (void);
В результате успешного вызова fork()
ядро создаёт новый процесс, который является почти точной копией вызывающего процесса. Другими словами, новый процесс выполняет копию той же программы, что и создавший его процесс, при этом все его объекты данных имеют те же самые значения, что и в вызывающем процессе. Созданный процесс называется дочерним процессом, а процесс, осуществивший вызов fork()
, называется родительским.
После вызова родительский процесс и его вновь созданный потомок выполняются одновременно, при этом оба процесса продолжают выполнение с оператора, который следует сразу же за вызовом fork()
. Процессы выполняются в разных адресных пространствах, поэтому прямой доступ к переменным одного процесса из другого процесса невозможен.
Следующая короткая программа более наглядно показывает работу вызова fork()
и использование процесса:
#include <stdio.h>
#include <unistd.h>
int main ()
{
pid_t pid; /* идентификатор процесса */
printf ("Пока всего один процесс\n");
pid = fork (); /* создание нового процесса */
printf ("Уже два процесса\n");
if (pid == 0) {
printf ("Это Дочерний процесс, его pid=%d\n", getpid());
printf ("А pid его Родительского процесса=%d\n", getppid());
}
else if (pid > 0)
printf ("Это Родительский процесс pid=%d\n", getpid());
else
printf ("Ошибка вызова fork, потомок не создан\n");
}
Для корректного завершения дочернего процесса в родительском процессе необходимо использовать функцию wait()
или waitpid()
:
pid_t wait (int *status);
pid_t waitpid (pid_t pid, int *status, int options);
Функция wait()
приостанавливает выполнение родительского процесса до тех пор, пока дочерний процесс не прекратит выполнение или до появления сигнала, который либо завершает текущий процесс, либо требует вызвать функцию-обработчик. Если дочерний процесс к моменту вызова функции уже завершился (так называемый «зомби»), то функция немедленно возвращается. Системные ресурсы, связанные с дочерним процессом, освобождаются.
Функция waitpid()
приостанавливает выполнение родительского процесса до тех пор, пока дочерний процесс, указанный в параметре pid
, не завершит выполнение, или пока не появится сигнал, который либо завершает родительский процесс, либо требует вызвать функцию-обработчик. Если указанный дочерний процесс к моменту вызова функции уже завершился (так называемый «зомби»), то функция немедленно возвращается. Системные ресурсы, связанные с дочерним процессом, освобождаются.
Параметр pid
может принимать несколько значений:
pid < -1
означает, что нужно ждать любой дочерний процесс, чей идентификатор группы процессов равен абсолютному значениюpid
.pid = -1
означает ожидать любой дочерний процесс; функцияwait
ведет себя точно так же.pid = 0
означает ожидать любой дочерний процесс, чей идентификатор группы процессов равен таковому у текущего процесса.pid > 0
означает ожидать дочерний процесс, чей идентификатор равенpid
.
Значение options
создается путем битовой операции ИЛИ над следующими константами:
WNOHANG
- означает вернуть управление немедленно, если ни один дочерний процесс не завершил выполнение.WUNTRACED
- означает возвращать управление также для остановленных дочерних процессов, о чьем статусе еще не было сообщено.
Каждый дочерний процесс при завершении работы посылает своему процессу-родителю специальный сигнал SIGCHLD
, на который у всех процессов по умолчанию установлена реакция "игнорировать сигнал". Наличие такого сигнала совместно с системным вызовом waitpid()
позволяет организовать асинхронный сбор информации о статусе завершившихся порожденных процессов процессом-родителем.
Для перегрузки исполняемой программы можно использовать функции семейства exec
. Основное отличие между разными функциями в семействе состоит в способе передачи параметров.
int execl (char *pathname, char *arg0, arg1, ..., argn, NULL);
int execle (char *pathname, char *arg0, arg1, ..., argn, NULL, char **envp);
int execlp (char *pathname, char *arg0, arg1, ..., argn, NULL);
int execlpe (char *pathname, char *arg0, arg1, ..., argn, NULL, char **envp);
int execv (char *pathname, char *argv[]);
int execve (char *pathname, char *argv[], char **envp);
int execvp (char *pathname, char *argv[]);
int execvpe (char *pathname, char *argv[], char **envp);
Задание
- Изучить теоретическую часть лабораторной работы.
- Написать программу, создающую два дочерних процесса с
использованием двух вызовов
fork()
. Родительский и два дочерних процесса должны выводить на экран свойpid
иpid
родительского процесса и текущее время в формате:часы : минуты : секунды : миллисекунды
. Используя вызовsystem()
, выполнить командуps -x
в родительском процессе. Найти свои процессы в списке запущенных процессов. - Выполнить индивидуальное задание.
Варианты индивидуальных заданий:
- Написать программу нахождения массива K последовательных значений функции
y[i]=sin(2*PI*i/N)
(где i=0, 1, 2...K-1) с использованием ряда Тейлора. Пользователь задаёт значения K, N и количество n членов ряда Тейлора. Для расчета каждого члена ряда Тейлора запускается отдельный поток. Каждый поток выводит на экран свойpid
и рассчитанное значение ряда. Головной процесс суммирует все члены ряда Тейлора, и полученное значениеy[i]
записывает в файл. - Написать программу синхронизации двух каталогов, например,
Dir1
иDir2
. Пользователь задаёт именаDir1
иDir2
. В результате работы программы файлы, имеющиеся вDir1
, но отсутствующие вDir2
, должны скопироваться вDir2
вместе с правами доступа. Процедуры копирования должны запускаться в отдельном процессе для каждого копируемого файла. Каждый процесс выводит на экран свойpid
, имя копируемого файла и число скопированных байт. Число одновременно работающих процессов не должно превышать N (вводится пользователем). - Написать программу поиска одинаковых по их содержимому файлов в двух каталогов, например,
Dir1
иDir2
. Пользователь задаёт именаDir1
иDir2
. В результате работы программы файлы, имеющиеся вDir1
, сравниваются с файлами вDir2
по их содержимому. Процедуры сравнения должны запускаться в отдельном процессе для каждой пары сравниваемых файлов. Каждый процесс выводит на экран свойpid
, имя файла, общее число просмотренных байт и результаты сравнения. Число одновременно работающих процессов не должно превышать N (вводится пользователем). - Написать программу поиска заданной пользователем комбинации из m байт (m < 255) во всех файлах текущего каталога. Пользователь задаёт имя каталога. Главный процесс открывает каталог и запускает для каждого файла каталога отдельный процесс поиска заданной комбинации из m байт. Каждый процесс выводит на экран свой
pid
, имя файла, общее число просмотренных байт и результаты поиска. Число одновременно работающих процессов не должно превышать N (вводится пользователем). - Разработать программу «интерпретатор команд», которая воспринимает команды, вводимые с клавиатуры, (например,
ls -l /bin/bash
) и осуществляет их корректное выполнение. Для этого каждая вводимая команда должна выполняться в отдельном процессе с использованием вызоваexec()
. Предусмотреть контроль ошибок. - Создать дерево процессов по индивидуальному заданию. Каждый процесс постоянно, через время t, выводит на экран следующую информацию: номер процесса/потока, pid, ppid текущее время (мсек). Время
t=(номер процесса/потока по дереву)*200
(мсек).
Контрольные вопросы
- Работа с процессами в языке C.
- Использование функций семейства
exec
.
Источники
Алексеев И.Г. Учебно-методическое пособие Операционные системы и системное программирование: для студ. спец. «Программное обеспечение информационных технологий»/ И.Г Алексеев, П.Ю. Бранцевич – Мн.: БГУИР, 2009. – 73 с.