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

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

  Все выпуски  

Программирование в Linux с нуля [19.10.2007]


Программирование в Linux с нуля [19.10.2007]

Здравствуйте! Это очередной выпуск рассылки "Программирование в Linux с нуля".

--- новости ---

Книга "Программирование в Linux с нуля" версия 0.093

Tarball: ftp://ftp.lindevel.ru/zlp/zlp-0.093.tar.gz
Online: http://www.lindevel.ru/zlp


Сайт Lindevel.Ru перешел на новую систему управления контентом

Сайт Lindevel.Ru переведен на новый движок и пополняется новыми информационными материалами. В ближайшее время планируется перевод форума на новый движок с сохранением базы данных пользователей и сообщений.


Лента новостей

На сайте Lindevel.Ru запущена регулярно обновляемая лента новостей. Пожелания по поводу возможного подключения RSS и/или ATOM направляйте в форум.

Новые материалы книги

6.3. Порождение процесса

Как уже говорилось ранее, процесс в Linux - это нечто, выполняющее программный код. Этот код называют образом процесса (process image). Рассмотрим простой пример, когда вы находитесь в оболочке bash и выполняете команду ls. В этом случае происходит следующее. Образ программы-оболочки bash выполняется в процессе #1. Затем вы вводите команду ls, и оболочка определяет, что нужно запустить внешнюю программу (/bin/ls). Тогда процесс #1 создает свою почти точную копию, процесс #2, который выполняет тот же самый программный код. После этого процесс #2 заменяет свой текущий образ (оболочку) другим образом (программой /bin/ls). В итоге получаем отдельный процесс, выполняющий отдельную программу.

"К чему такая путаница?" - спросите вы. Зачем сначала "клонировать" процесс, а затем заменять в нем образ? Не проще ли все делать одной-единственной операцией? Ответы на подобные вопросы дать тяжело, но, как правило, с опытом прихоидит понимание того, что подобная схема является одной из граней красоты Unix-систем.

Попробуем все-таки разобраться, почему в Unix-системах порождение процесса отделено от запуска программы. Для этого выясним, что же происходит с данными при "клонировании" процесса. Итак, каждый процесс хранит в своей памяти различные данные (переменные, файловые дескрипторы и проч.). При порождении нового процесса, потомок получает точную копию данных родителя. Но как только новый процесс создан, родитель и потомок уже распоряжаются своими копиями по своему усмотрению. Это позволяет распараллелить программу, заставив ее выполнять какой-нибудь трудоемкий алгоритм в отдельном процессе.

Может быть кто-то из вас слышал про то, что в Linux есть потоки, которые позволяют в одной программе реализовывать параллельное выполнение нескольких функций. Опять же возникает вопрос: "Если есть потоки, зачем вся эта головомойка с клонированиями и заменой образов?". А дело в том, что потоки работают с общими данными и выполняются в одной программе. Если в потоке произошло что-то страшное, то это, как правило, отражается на всей программе в целом. Хотя технически потоки реализованы в Linux на базе процессов, но процесс все же является более независимой единицей. Крах дочернего процесса никак не отражается на работе родителя, если сам родитель этого не пожелает.

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

Разберемся теперь с тем, как на практике происходит "клонирование" процессов. Для этого используется простой системный вызов fork(), прототип которого находится в файле unistd.h:


pid_t fork (void);

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


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

int main (void)
{
        pid_t pid = fork ();

        if (pid == 0) {
                printf ("child (pid=%d)\n", getpid());
        } else {
                printf ("parent (pid=%d, child's pid=%d)\n", getpid(), pid);
        }

        return 0;
}

Проверяем, что получилось:


$ gcc -o fork01 fork01.c
$ ./fork01
child (pid=21026)
parent (pid=21025, child's pid=21026)

Обратите внимание, что поскольку после вызова fork() программу выполняли уже два независимых процесса, то сообщение родителя вполне могло бы появиться первым.

Контакты

Сайт проекта Lindevel.Ru (http://www.lindevel.ru) посвящен программированию в Linux. Здесь вы всегда сможете найти последнюю версию книги, а также оставить вопросы и пожелания в форуме (http://forum.lindevel.ru). E-mail автора книги nn at lindevel dot ru (Nikolay N. Ivanov).


Рассылки Subscribe.Ru
FreeBSD

В избранное