Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Laba_2.doc
Скачиваний:
1
Добавлен:
01.05.2025
Размер:
122 Кб
Скачать
☆

2. Создание многопроцессных программы на языке Си с использованием системных вызовов Unix

Любая программа в Unix-системах выполняется в виде одного (корневого) процесса или набора процессов. В лабораторной работе №1 мы уже рассмотрели, как происходит запуск программы, становимся теперь на том, как это происходит с точки зрения реализации на Си с использованием системных вызовов Unix.

Программно порождение процессов осуществляется с использованием системного вызова fork() – после выполнения этого вызова в системе появляется процесс, который является точной копией процесса, который выдал данный системный вызов. Но для запуска программ одного вызова fork() не достаточно – необходим механизм позволяющий загрузить бинарный код программы в оперативную память. Такой механизм предоставляет функции группы execl(execl, execlp, execle, execv, execvp). Функция данной группы осуществляет подмену кода процесса ее вызвавшего бинарным кодом загружаемой программы(Пример 2.2).

Когда вы в командном интерпретаторе набираете команду Например $ps - фрагмент кода программы запускающий данную команду будет выглядеть примерно так:

Пример 2.2 Запуск команды ps в командном интерпретаторе

main()

int st;

…

if (fork()==0)

execlp("ps" , "ps", 0);

wait(&st);

Остановимся теперь более подробно на функциях порождения и замещения процессов. Для начала дадим несколько утверждений:

o Процесс, который инициировал системный вызов fork(), принято называть родительским процессом (parent process).

o Вновь порожденный процесс принято называть процессом потомком (child process).

o Процесс потомок является почти полной копией родительского процесса

o Процесс родитель и процесс потомок разделяют один и тот же кодовый сегмент. Системный вызов fork() в случае успеха возвращает родительскому процессу идентификатор потомка, а потомку 0. В ситуации, когда процесс не может быть создан функция fork() возвращает -1.

При программировании процессов вам понадобится следующее:

a) Аргументы функции main:

void main(int argc, char *argv[], char *envp[]);

Если вы наберете команду $ a.out a1 a2 a3,где a.out – имя запускаемой вами программы, то функция main программы из файла a.out вызовется с:

argc = 4 /* количество аргументов */

argv[0] = "a.out" argv[1] = "a1"

argv[2] = "a2" argv[3] = "a3"

argv[4] = NULL

По соглашению argv[0] содержит имя выполняемого файла.

b) Информация о так называемом "окружении" (вспомните переменные окружения описанные в лабораторной работе №1) char *envp[], продублированного также в предопределенной переменной extern char **environ;

Окружение состоит из строк вида

"ИМЯПЕРЕМЕННОЙ=значение"

Массив этих строк завершается NULL (как и argv). Для получения значения переменной с именем ИМЯ существует стандартная функция

char *getenv( char *ИМЯ );

Она выдает либо значение, либо NULL если переменной с таким именем нет.

c) Информация об открытых по умолчанию файлов. По умолчанию (неявно) всегда открыты 3 канала:

ВВОД В Ы В О Д

FILE * stdin stdout stderr

соответствует fd 0 1 2

Эти каналы достаются процессу "в наследство" от запускающего процесса и связаны с дисплеем и клавиатурой, если только не были перенаправлены.

Кроме того, программа может сама явно открывать файлы (при помощи системных вызовов open, creat, pipe, fopen и т.п.). Всего программа может одновременно открыть до 20 файлов (считая стандартные каналы), а в некоторых системах и больше (например, 64).

d) Получение информации об уникальном номере процесса потомка и процесса-родителя и др.

Пример 2.3 Системные вызовы для получения идентификаторов процесса

#include <stream.h>

#include <sys/types.h>

#include <unistd.h>

main ( )

{

cout << " Идентификатор текущего процесса PID: " << getpid() <<” \n”;

cout << " Идентификатор родительского процесса- PPID: " << getppid()<<” \n”;

cout << " Идентификатор группы процесса PGID: " << getpgrp()<<” \n”;

cout << " Идентификатор пользователя –real UID: " << getuid() <<” \n”;

cout << " Реальный идентификатор группы пользователя real -GID:" <<

getgid()<<” \n”;

cout << " Эффектифный идентификатор пользователя - UID: " <<

geteuid()<<” \n”;

cout << " Эффектифный идентификатор группы пользователя GID: " <<

getegid()<<” \n”;

exit(0);

}

е) Текущий каталог - достается в наследство от процесса-"родителя", и может быть затем изменен системным вызовом

chdir(char *имя_нового_каталога);

В командном режиме вы можете получить информацию о текущем каталоге, набрав команду $pwd.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]