Московский физико-технический институт
Опубликован: 16.09.2004 | Доступ: свободный | Студентов: 7773 / 1592 | Оценка: 4.44 / 4.28 | Длительность: 15:33:00
Лекция 2:

Процессы в операционной системе UNIX

< Лекция 1 || Лекция 2: 1234 || Лекция 3 >

Создание процесса в UNIX. Системный вызов fork()

В операционной системе UNIX новый процесс может быть порожден единственным способом – с помощью системного вызова fork() . При этом вновь созданный процесс будет являться практически полной копией родительского процесса. У порожденного процесса по сравнению с родительским процессом (на уровне уже полученных знаний) изменяются значения следующих параметров:

  • идентификатор процесса PID ;
  • идентификатор родительского процесса PPID .

Дополнительно может измениться поведение порожденного процесса по отношению к некоторым сигналам, о чем подробнее будет рассказано на семинарах 13–14, когда мы будем говорить о сигналах в операционной системе UNIX.

Системный вызов для порождения нового процесса

Прототип системного вызова

#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);

Описание системного вызова

Системный вызов fork служит для создания нового процесса в операционной системе UNIX. Процесс, который инициировал системный вызов fork , принято называть родительским процессом ( parent process ). Вновь порожденный процесс принято называть процессом-ребенком ( child process ). Процесс-ребенок является почти полной копией родительского процесса. У порожденного процесса по сравнению с родительским изменяются значения следующих параметров:

  • идентификатор процесса;
  • идентификатор родительского процесса;
  • время, оставшееся до получения сигнала SIGALRM ;
  • сигналы, ожидавшие доставки родительскому процессу, не будут доставляться порожденному процессу.

При однократном системном вызове возврат из него может произойти дважды: один раз в родительском процессе, а второй раз в порожденном процессе. Если создание нового процесса произошло успешно, то в порожденном процессе системный вызов вернет значение 0, а в родительском процессе – положительное значение, равное идентификатору процесса-ребенка. Если создать новый процесс не удалось, то системный вызов вернет в инициировавший его процесс отрицательное значение.

Системный вызов fork является единственным способом породить новый процесс после инициализации операционной системы UNIX.

В процессе выполнения системного вызова fork() порождается копия родительского процесса и возвращение из системного вызова будет происходить уже как в родительском, так и в порожденном процессах. Этот системный вызов является единственным, который вызывается один раз, а при успешной работе возвращается два раза (один раз в процессе-родителе и один раз в процессе-ребенке)! После выхода из системного вызова оба процесса продолжают выполнение регулярного пользовательского кода, следующего за системным вызовом.

Прогон программы с fork() с одинаковой работой родителя и ребенка

Для иллюстрации сказанного давайте рассмотрим следующую программу:

/* Программа 03-1.с – пример создания нового
   процесса с одинаковой работой процессов 
   ребенка и родителя */ 

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
    pid_t pid, ppid;
    int a = 0; 
    (void)fork();

    /* При успешном создании нового процесса
       с этого места псевдопараллельно 
       начинают работать два процесса: старый
       и новый */
    /* Перед выполнением следующего выражения 
       значение переменной a в обоих процессах
       равно 0 */

    a = a+1;

    /* Узнаем идентификаторы текущего и роди-
       тельского процесса (в каждом из 
       процессов !!!) */

    pid = getpid();
    ppid = getppid();

    /* Печатаем значения PID, PPID и вычислен-
       ное значение переменной a (в каждом из
       процессов !!!) */
    printf("My pid = %d, my ppid = %d, 
      result = %d\n", (int)pid, (int)ppid, a);
    return 0;
}
Листинг 3.1. Программа 03-1.с – пример создания нового процесса с одинаковой работой процессов ребенка и родителя.

Наберите эту программу, откомпилируйте ее и запустите на исполнение (лучше всего это делать не из оболочки mc, так как она не очень корректно сбрасывает буферы ввода-вывода). Проанализируйте полученный результат.

Системный вызов fork() (продолжение)

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

pid = fork();
if(pid == -1){
    ...
    /* ошибка */
    ...
} else if (pid == 0){
    ...
    /* ребенок */
    ...
} else {
    ...
    /* родитель */
    ...
}

Написание, компиляция и запуск программы с использованием вызова fork() с разным поведением процессов ребенка и родителя

Измените предыдущую программу с fork() так, чтобы родитель и ребенок совершали разные действия (какие – не важно).

< Лекция 1 || Лекция 2: 1234 || Лекция 3 >
лия логовина
лия логовина

организовать двустороннюю поочередную связь процесса-родителя и процесса-ребенка через pipe, используя для синхронизации сигналы sigusr1 и sigusr2.

Макар Оганесов
Макар Оганесов