
учебник
.pdfи exec(). Системный вызов fork() создает новый процесс, у которого пользовательский контекст совпадает с пользовательским контекстом процесса-родителя. Системный вызов exec() изменяет пользовательский контекст текущего процесса, не создавая новый процесс.
Для иллюстрации использования системного вызова exec() рассмотрим следующие программы
Программа 3-04, изменяющая пользовательский контекст процесса (запускающая другую программу)
#include <sys/types.h> #include <unistd.h> #include <stdio.h>
int main(int argc, char *argv[], char *envp[])
{
/*Мы будем запускать команду cat c аргументом командной строки 03-2.с без изменения параметров среды, т.е. фактически выполнять команду "cat 03-2.c", которая должна выдать содержимое данного файла на экран. Для функции execle в качестве имени программы мы указываем ее полное имя с путем от корневой директории —/bin/cat. Первое слово в командной строке у нас должно совпадать с именем запускаемой программы. Второе слово в командной строке – это имя файла, содержимое которого мы хотим распечатать. */
(void) execle("/bin/cat", "/bin/cat", "03-2.c", NULL, envp);
/* Сюда попадаем только при возникновении ошибки */ printf("Error on program start\n");
exit(-1); return 0;
}
Листинг 3-04. Программа, изменяющая пользовательский контекст процесса.
61
Программа 3-05, изменяющая пользовательский контекст процесса, пример использования функции execv
#include<iostream> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <signal.h> #include <cstdlib> using namespace std; intmain()
{
pid_tpid; // прототип системного вызова pid=fork();// тут происходит разделение
switch (pid)
{
case -1:
cout<<"error";// в случае возврата fork`ом -1, это считается ошибкой break;
case 0:
execlp("/bin/ps","ps",NULL);// процесс-потомок выводит запущеные процессы
exit(0);
default:
wait(0);// процесс-родитель ждет завершения процесса-потомка
execlp("who","who",NULL);//процессу-родителю поручаем вывести пользователей
exit(0);
}
return 0;
}
Листинг 3-05. Программа, изменяющая контекст процесса
62
Порядок выполнения работы
1.Рассмотреть утилиты ps и top. Для утилиты ps рассмотреть основные ключи, используя man ps, ps –help. Выполнить команду ps со всеми основными ключами. Вывести иерархию процессов с подробным описанием. Вывести все системные процессы. Рассмотреть в дереве процессов различные типы процессов. Посмотреть место процесса init в иерархии процессов, посмотреть уровень загрузки системы по умолчанию. В каталоге /etc найти файл inittab и рассмотреть его формат. Объяснить, что получится в результате выполнения утилиты /sbin/init с параметрами 1, 3, 5, 6, 0;
2.Рассмотреть компиляцию программ с использованием компиляторов gcc и g++;
3.Изучить функции управления процессами (использовать man). Написать многопроцессную программу на Си или C++, реализующую запуск команд UNIX из процессов. Реализовать синхронизацию процессов-родителей с процессами-потомками (использовать функцию wait).
4.В качестве примера использования системных вызовов getpid() и getppid() самостоятельно напишите программу, печатающую значения PID и PPID для текущего процесса. Запустите ее несколько раз подряд. Посмотрите, как меняется идентификатор текущего процесса. Объясните наблюдаемые изменения.
5.Наберите программы, представленные в тексте лабораторного практикума, откомпилируйте и запустите на исполнение. Проанализируйте полученные результаты.
6.В качестве примера самостоятельно напишите программу, распечатывающую значения аргументов командной строки и параметров окружающей среды для текущего процесса.
7.Для закрепления полученных знаний модифицируйте программу, созданную при выполнении задания раздела "Написание, компиляция и запуск программы с использованием вызова fork() с разным поведением процессов-ребенка и родителя" так, чтобы порожденный процесс запускал на исполнение новую (любую) программу.
63
Варианты индивидуальных заданий
1.Написать программу, реализующую меню из трех пунктов: 1-й пункт: ввести пользователя и вывести на экран все процессы, запущенные данным пользователем; 2-й пункт: показать всех пользователей, в настоящий момент, находящихся в системе; 3-й пункт: завершение.
2.Написать программу, реализующую меню из трех пунктов: 1-й пункт: вывести всех пользователей, в настоящее время работающих в системе; 2-й пункт: послать сообщение пользователю, имя пользователя, терминал и сообщение вводятся с клавиатуры; 3-й пункт: завершение.
3.Написать программу, реализующую меню из трех пунктов: 1-й пункт: показать все процессы пользователя, запустившего данный командный файл; 2-й пункт: послать сигнал завершения процессу текущего пользователя (ввести PID процесса); 3-й пункт: завершение.
4.Написать командный файл, подсчитывающий количество активных терминалов пользователя (имя пользователя вводится с клавиатуры).
5.Написать командный файл, посылающий сообщение всем активным пользователям (сообщение находится в файле).
6.Написать командный файл, посылающий сигнал завершения процессам текущего пользователя. Символьная маска имени процесса вводится с клавиатуры.
7.Написать командный файл, подсчитывающий количество определенных процессов пользователя (ввести имя пользователя и название процесса).
8.Реализовать Меню из двух пунктов: 1-й пункт: определить количество запущенных данным пользователем процессов bash (предусмотреть ввод имени пользователя); 2-й пункт: завершить все процессы bash данного пользователя.
9.Реализовать Меню из трех пунктов: 1-й пункт: поиск файла в каталоге, <Имя файла> и <Имя каталога> вводятся пользователем; 2-й пункт: копирование одного файла в другой каталог, <Имя файла> и <Имя каталога> вводятся; 3-й пункт: завершение командного файла.
64
10 Написать командный файл, который в цикле по нажатию клавиши выводит информацию о системе, активных пользователях в системе, а для введенного имени пользователя выводит список активных процессов данного пользователя.
11 Реализовать командный файл, который при старте выводит информацию о системе, информацию о пользователе, запустившем данный командный файл, далее в цикле выводит список активных пользователей в системе – запрашивает имя пользователя и выводит список всех процессов bash, запущенных данным пользователем.
12 Реализовать командный файл, позволяющий в цикле посылать всем активным пользователям сообщение – сообщение вводится с клавиатуры. Командный файл при старте выводит имя компьютера, имя запустившего командный файл пользователя, тип операционной системы, IP-адрес машины.
13 Реализовать командный файл, позволяющий в цикле посылать всем активным пользователям (исключая пользователя, запустившего данный командный файл) сообщение – сообщение вводится с клавиатуры. Командный файл при старте выводит имя компьютера, имя запустившего командный файл пользователя, тип операционной системы, список загруженных модулей.
14 Реализовать командный файл, который при старте выводит информацию о системе, информацию о пользователе, запустившем данный командный файл, далее в цикле выводит список активных пользователей в системе – запрашивает имя пользователя и выводит список всех терминалов, на которых зарегистрирован этот пользователь.
15 Реализовать командный файл, который выводит: дату, информацию о системе, текущий каталог, текущего пользователя, настройки домашнего каталога текущего пользователя, далее в цикле выводит список активных пользователей – запрашивает имя пользователя и выводит информацию об активности данного пользователя.
16 Реализовать командный файл, который выводит: дату в формате «день – месяц – год – время», информацию о системе в формате: имя компьютера : версия ОС : IP адрес : имя текущего пользователя : текущий каталог, выводит настройки домашнего каталога текущего пользователя и основные переменные окружения. Далее в
65
цикле выводит список активных пользователей – запрашивает имя пользователя и выводит информацию об активности введенного пользователя.
17 Реализовать программу, реализующую символьное меню (в цикле): 1-й пункт: вывод полной информации о файлах каталога (ввести имя каталога для отображения); 2-й пункт: изменить атрибуты файла: файл вводится с клавиатуры по запросу, атрибуты, которые требуется установить, тоже вводятся. После изменения атрибутов вывести на экран расширенный список файлов для проверки установленных атрибутов; 3-й пункт: выход. При старте программа выводит информацию об имени компьютера, IP-адреса и список всех пользователей, зарегистрированных в данный момент на компьютере.
18 Реализовать программу, реализующую символьное меню( в цикле) 1-й пункт: вывод полной информации о файлах каталога (ввести имя каталога для отображения); 2-й пункт: создать командный файл: файл вводится с клавиатуры по запросу, далее изменяются атрибут файла на исполнение, затем вводится с клавиатуры строка, которую будет исполнять командный файл. После изменения атрибутов вывести на экран расширенный список файлов для проверки установленных атрибутов и запустить созданный командный файл; 3-й пункт; выход. При старте командный файл выводит информацию об имени компьютера, IPадреса и список всех пользователей зарегистрированных в данный момент на компьютере.
19 Написать командный файл реализующий символьное меню: 1-й пункт: работа с информационными командами (реализовать все основные информационные команды); 2-й пункт: Копирование файлов: в этом пункте выводится информация о содержимом текущего каталога, далее предлагается интерфейс копирования файла: ввод имени файла и ввод каталога для копирования. По выполнению пункта выводится содержимое каталога, куда был скопирован файл, и выводится содержимое скопированного файла; 3-й пункт: выход .
66
Контрольные вопросы
Назовите компоненты операционной системы.
Какие действия по управлению процессами выполняет ОС?Что такое процесс? Его контекст. Понятие многозадачности.Что такое стек процесса?
Идентификация процесса. Иерархия процессов.
Опишите возможные состояния процесса. Краткая диаграмма состояний.
Понятие системного вызова. Перечислите системные вызовы, рассматриваемые в данной лабораторной работе.
Опишите системные вызовы getuid() и getgid().Опишите системные вызовы getppid() и getpid().
Создание процесса в UNIX. Системный вызов fork().Завершение процесса. Функция exit().
Изменение пользовательского контекста процесса.Семейство функций для системного вызова exec().
Предположим, вам нужно разработать новую компьютерную архитектуру, которая вместо использования прерываний осуществляет аппаратное переключение процессов. Какие сведения необходимы центральному процессору? Опишите возможное устройство аппаратного переключения процессов.
На всех ныне существующих компьютерах хотя бы часть обработчиков прерываний написаны на ассемблере. Почему?
Когда в результате прерывания или системного вызова управление передается операционной системе, используется, как правило, область стека ядра, отделенная от стека прерываемого процесса. Почему?
67
Лабораторная работа 4 ОРГАНИЗАЦИЯ ВЗАИМОДЕЙСТВИЯ ПРОЦЕССОВ
С ПОМОЩЬЮ КАНАЛОВ
Цели и задачи
Изучить переназначение операций ввода-вывода. Научиться использовать каналы для организации взаимодействия процессов и их синхронизации.
4.1 Понятие о потоке ввода-вывода
Канал связи (англ. channel, data line) — система технических средств и среда распространения сигналов для передачи сообщений (не только данных) от источника к получателю (и наоборот). Канал связи, понимаемый в узком смысле (тракт связи), представляет только физическую среду распространения сигналов, например, физическую линию связи
Каналы связи в зависимости от способа передачи сигналов классифицируют на несколько видов. Симплексный канал направляет сигналы только в одном направлении. Полудуплексный канал позволяет передать сигналы в двух направлениях, но поочередно. Такая передача экономически целесообразна также в любых типах каналов при взаимодействии партнеров типа запрос-ответ, когда перед ответом необходимо время для обработки запроса.
Когда процесс создает канал, ядро устанавливает два файловых дескриптора для пользования этим каналом. Первый дескриптор используется, чтобы открыть путь ввода в канал (запись), в то время как второй применяется для получения данных из канала (чтение).
Данные, идущие через канал, проходят через ядро. В операционной системе каналы представлены корректным inode - индексным дескриптором, который существует в пределах самого ядра, а не в какой-либо физической файловой системе.
Среди всех категорий средств коммуникации наиболее употребительными являются каналы связи, обеспечивающие достаточно безопасное и достаточно информативное взаимодействие процессов.
Существует две модели передачи данных по каналам связи – поток ввода-вывода и сообщения. Из них более простой является
68
потоковая модель, в которой операции передачи/приема информации вообще не интересуются содержимым того, что передается или принимается. Вся информация в канале связи рассматривается как непрерывный поток байт, не обладающий никакой внутренней структурой.
Понятие о pipe. Системный вызов pipe()
Наиболее простым способом для передачи информации с помощью потоковой модели между различными процессами или даже внутри одного процесса в операционной системе UNIX является pipe (канал, труба, конвейер).
Важное отличие pip’а от файла заключается в том, что прочитанная информация немедленно удаляется из него и не может быть прочитана повторно.
Pipe можно представить себе в виде трубы ограниченной емкости, расположенной внутри адресного пространства операционной системы, доступ к входному и выходному отверстию которой осуществляется с помощью системных вызовов. В действительности pipe представляет собой область памяти, недоступную пользовательским процессам напрямую, зачастую организованную в виде кольцевого буфера (хотя существуют и другие виды организации). По буферу при операциях чтения и записи перемещаются два указателя, соответствующие входному и выходному потокам. При этом выходной указатель никогда не может обогнать входной и наоборот. Для создания нового экземпляра такого кольцевого буфера внутри операционной системы используется
системный вызов pipe().
Прототип системного вызова
#include <unistd.h> int pipe(int *fd);
Описание системного вызова
Системный вызов pipe предназначен для создания pipe внутри операционной системы.
Параметр fd является указателем на массив из двух целых переменных. При нормальном завершении вызова в первый элемент
69
массива – fd[0] – будет занесен файловый дескриптор, соответствующий выходному потоку данных pipe и позволяющий выполнять только операцию чтения, а во второй элемент массива – fd[1] – будет занесен файловый дескриптор, соответствующий входному потоку данных и позволяющий выполнять только операцию записи.
Возвращаемые значения Системный вызов возвращает значение 0 при нормальном завершении
изначение -1 при возникновении ошибок.
Впроцессе работы системный вызов организует выделение области памяти под буфер и указатели и заносит информацию, соответствующую входному и выходному потокам данных, в два элемента таблицы открытых файлов, связывая тем самым с каждым pip’ом два файловых дескриптора. Для одного из них разрешена только операция чтения из pip’а, а для другого – только операция записи в pipe . Для выполнения этих операций мы можем использовать те же самые системные вызовы read() и write(), что и при работе с файлами. Естественно, по окончании использования входного или/и выходного потока данных, нужно закрыть соответствующий поток с помощью системного вызова close() для освобождения системных ресурсов. Необходимо отметить, что, когда все процессы, использующие pipe, закрывают все ассоциированные с ним файловые дескрипторы, операционная система ликвидирует pipe. Таким образом, время существования pip’а в системе не может превышать время жизни процессов, работающих с ним.
Программа 4-01.с, иллюстрирующая работу с pip'ом в рамках
одного процесса.
Пример создания pip'a, записи в него данных, чтения из него и освобождению выделенных ресурсов. Прогон программы для pipe в одном процессе
#include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <iostream>
70