организовать двустороннюю поочередную связь процесса-родителя и процесса-ребенка через pipe, используя для синхронизации сигналы sigusr1 и sigusr2. |
Процессы в операционной системе UNIX
Изменение пользовательского контекста процесса. Семейство функций для системного вызова exec()
Для изменения пользовательского контекста процесса применяется системный вызов exec() , который пользователь не может вызвать непосредственно. Вызов exec() заменяет пользовательский контекст текущего процесса на содержимое некоторого исполняемого файла и устанавливает начальные значения регистров процессора (в том числе устанавливает программный счетчик на начало загружаемой программы). Этот вызов требует для своей работы задания имени исполняемого файла, аргументов командной строки и параметров окружающей среды. Для осуществления вызова программист может воспользоваться одной из шести функций: execlp() , execvp() , execl() и, execv() , execle() , execve() , отличающихся друг от друга представлением параметров, необходимых для работы системного вызова exec() . Взаимосвязь указанных выше функций изображена на рисунке 3–4.3.
Поскольку системный контекст процесса при вызове exec() остается практически неизменным, большинство атрибутов процесса, доступных пользователю через системные вызовы ( PID , UID, GID, PPID и другие, смысл которых станет понятен по мере углубления наших знаний на дальнейших занятиях), после запуска новой программы также не изменяется.
Важно понимать разницу между системными вызовами fork() и exec() . Системный вызов fork() создает новый процесс, у которого пользовательский контекст совпадает с пользовательским контекстом процесса-родителя. Системный вызов exec() изменяет пользовательский контекст текущего процесса, не создавая новый процесс.
Прогон программы с использованием системного вызова exec()
Для иллюстрации использования системного вызова exec() давайте рассмотрим следующую программу
/* Программа 03-2.с, изменяющая пользователь- ский контекст процесса (запускающая другую программу) */ #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", 0, envp); /* Сюда попадаем только при возникновении ошибки */ printf("Error on program start\n"); exit(-1); return 0; /* Никогда не выполняется, нужен для того, чтобы компилятор не выдавал warning */ }Листинг 3.2. Программа 03-2.с, изменяющая пользовательский контекст процесса
Откомпилируйте ее и запустите на исполнение. Поскольку при нормальной работе будет распечатываться содержимое файла с именем 03-2.c, такой файл при запуске должен присутствовать в текущей директории (проще всего записать исходный текст программы под этим именем). Проанализируйте результат.
Написание, компиляция и запуск программы для изменения пользовательского контекста в порожденном процессе
Для закрепления полученных знаний модифицируйте программу, созданную при выполнении задания раздела "Написание, компиляция и запуск программы с использованием вызова fork() с разным поведением процессов ребенка и родителя" так, чтобы порожденный процесс запускал на исполнение новую (любую) программу.