Отправляет email-рассылки с помощью сервиса Sendsay

Программирование и др.

  Все выпуски  

Программирование в Linux с нуля - Выпуск 9


Информационный Канал Subscribe.Ru

Рассылка проекта Lindevel.Ru

Программирование в Linux с нуля. Выпуск 9.

1. Предисловие

Здравствуйте, уважаемые подписчики. Материал этого выпуска касается не только Linux, но и всех Unix-систем. Мы продолжаем изучать многозадачность. Сегодня мы поговорим об архинужном и архиважном системном вызове fork(), без которого невозможна многозадачность в Unix. Материал этого выпуска может потребовать большого умственного напряжения.

Если вы обнаружите ошибки или неточности в рассылке, сообщайте об этом в форуме на Lindevel.Ru. Туда же отправляйте свои вопросы и комментарии.

2. Программа

2.1. Описание

По традиции начнем с программы. Наш пример (fork.c) создает новый процесс, выводит по информационному сообщению в каждом процессе и уводит оба эти процесса в бесконечные циклы.

fork.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main (void)
{
        printf ("Start...\n");

        if (fork ()) {
                fprintf (stderr, "New process with PID %d\n", (int) getpid());
                while (1);
        }
        else {
                fprintf (stderr, "Old process with PID %d\n", (int) getpid());
                while (1);
        }

        return 0;
}


2.3. Компиляция и запуск

Компиляция примера осуществляется командой gcc -o fork fork.c, а запуск - командой ./fork. Здесь нет ничего нового. После вывода победных сообщений, программа пускается в бесконечный цикл, из которого ее выводит комбинация клавиш <Ctrl+C> Можно, конечно, воспользоваться командой kill. В этом случае вас ждет сюрприз.

3. Теория

3.1. Философия многозадачности в Unix

Чтобы наверняка разобраться в философии многозадачности Linux требуется изучение исходных кодов ядра. Однако это не самая простая задача, и мы сейчас этого делать не будем. Я попытаюсь объяснить на пальцах красоту многозадачности Unix в этом выпуске рассылки.

Насколько мне известно, в Windows используется простейший механизм многозадачности: программа вызывает функцию (по-моему это spawn(), если не так - поправьте), которая запускает нужную программу. И все!

В Linux тоже есть функция system(), которая запускает другую программу аналогичным образом. Однако не стоит использовать эту функцию в серьезных программах, поскольку она потенциально несет в себе побочные эффекты.

В Unix все мощнее и оригинальнее. Подавляющее большинство книг по программированию в Unix/Linux искусственно упрощают описание механизма создания процесса, вводя читателей в заблуждение. Самым типичным примером является высказывание о том, что процесс изначально создает своию точную копию (клон). Попытаемся разобраться, что же происходит на самом деле.

В Unix с процессом ассоциируется так называемая нить выполнения. Нить выполнения - это набор последовательно выполняющихся комманд (код) и набор данных, которыми манипулирует этот код. Проще говоря, нить выполнения - это КОД+ДАННЫЕ. Чтобы понять, что такое нить выполнения, надо уметь видеть в программе не только код (инструкции, переменные и проч.), но и данные, связанные с этим кодом.

Многозадачность в Unix организована таким образом, что порождение нового процесса начинается с создания новой нити выполнения, использующей тот же код, но другие данные. Такое действие осуществляется при помощи функции fork(). Рассмотрим пример. Пусть в некотором процессе нить выполнения КОД1+ДАННЫЕ1 вызвала функцию fork(), которая создала нить выполнения КОД1+ДАННЫЕ2. Как известно, один и тот же код может выполняться по-разному в зависимости от данных. Такой код называется динамическим. То есть после вызова функции fork() один и тот же код может выполнять уже разные действия.

3.2. Системный вызов fork()

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

3.3. Разбор полетов

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

Не завершая программу попробуйте запустить другой терминал и вызвать там команду ps -ef. На экран будет выведен список работающих в системе процессов, из которого видно, что программе fork действительно соответствуют два процесса, один из которых является родительским для другого.

Заключение

Разберитесь основательно с материалом этого выпуска, поскольку это крайне необходимо для дальнейшего изучения многозадачности. Вопросы задавайте в форуме на сайте. В следующем выпуске мы изучим ряд функций, которые заставляют программу выполнять другой код.
Спасибо за внимание.

Николай.

Новости сайта Lindevel.Ru

Новые возможности:

  • Добавлена поддержка личных сообщений
  • Добавлена поддержка добавления комментариев для статей и новостей
  • Переход на новый файловый архив
  • Регистрация на сайте теперь не требует подтверждения по e-mail

Новые материалы:

  • Русский перевод книги Л. Торвальдса и Д. Даймонда "Just for fun" (Рассказ нечаянного революционера)

Рассылки Subscribe.Ru
*nix project - новости из мира unix-систем! (ежедневная)

http://subscribe.ru/
http://subscribe.ru/feedback/
Подписан адрес:
Код этой рассылки: comp.soft.prog.linuxp
Отписаться

В избранное