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

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

  Все выпуски  

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


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

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

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

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

Здравствуйте, уважаемые подписчики. В этом выпуске мы начнем изучать огромную тему, связанную с Linux - многозадачность.

Сайт проекта Lindevel.Ru начал полноценную работу. На сайте есть форум, где вы можете задавать свои вопросы (в том числе вопросы по рассылке).

2. Программа

2.1. Описание

Прежде, чем переходить к теории многозадачности, создадим простейшую программу, которая выводит идентификаторы текущего и родительского процессов. О том, что такое идентификаторы процессов, читайте далее.

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

int main (void)
{
        pid_t pid;
        pid_t ppid;

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

        printf ("%d\n%d\n", (int) pid, (int) ppid);

        return 0;
}


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

Программа состоит из одного исходного файла. Компиляция и сборка выполняются одной командой:


$ gcc -o pids pids.c
$

Можно, конечно, воспользоваться утилитой make, предварительно создав Makefile. Никто вас за это не осудит. Запускается программа командой ./pids из текущего каталога:


$ ./pids
11543
11448
$

Программа вывела на экран два целых числа. У каждого из вас эти числа буду своими. В данном случае это идентификатор текущего процесса и идентификатор родительского процесса. Если запустить программу повторно из того же терминала, то первое число изменится, а второе останется неизменным:


$ ./pids
11544
11448
$

Но если мы перезапустим терминал или воспользуемся другим терминалом, то изменятся оба числа:


$ ./pids
11585
11548
$ ./pids
11586
11548
$

Подумайте, что бы это могло значить?

3. Теория

3.1. Введение в многозадачность

Процессоры x86 (как и PowerPC и большинство остальных) не поддерживают многозадачность в буквальном смысле этого слова, но так назваемый защищенный режим процессоров предоставляет операционной системе хорошую возможность заставить пользователя верить в то, что несколько программ действительно выполняются одновременно. Даже на процессорах, не поддерживающих защищенный режим (например Intel 8086) можно организовать многозадачность. Грубо говоря, операционная система переключается от одной задачи к другой настолько быстро, что нам кажется, что они выполняются одновременно. А что же такое задача?

В Linux вместо понятия 'задача' используется понятие 'процесс'. Хотя это не совсем одно и то же, но эти тонкости нас сейчас не интересуют. Итак, процесс - это запущенный экземпляр программы. Мы можем запустить одну программу два раза (браузер, например), получив тем самым два процесса, основанных на одной программе. Понятия "процесс" и "программа" не эквивалентны.

3.2. Идентификаторы процессов

У каждой программы есть свое уникальное имя, а у каждого процесса - свой уникальный номер, который называют идентификатором процесса и обозначают PID (Process IDentifier). В работающей операционной системе не может быть двух процессов с одинаковыми идентификаторами. На 32-разрядных Intel-архитектурах (коих большинство в России и в странах ближнего зарубежья) PID представляет собой 16-разрядное целое число.

Чтобы получить список идентификаторов процессов, используют команду ps. Команда ps, вызванная без аргументов выводит очень скромный список:


$ ps
  PID TTY          TIME CMD
11548 pts/1    00:00:00 bash
11661 pts/1    00:00:00 ps
$

Это таблица процессов, запущенных под текущим терминалом. В данном примере - это командный интерпретатор bash и сама программа ps. Но если вызвать эту же программу с аргументами -fe (-f -e), то список будет много интереснее. У меня этот список занял 71 строку. Аргумент -e заставляет команду ps вывести список всех работающих в системе процессов, а аргумент -f позволяет выводить дополнительные данные.

Экспериментируя с командой ps, можно сделать интересные открытия, которые выходят за рамки настоящего выпуска рассылки.

3.3. Родители и дерево процессов

В Linux процессы порождаются (запускаются) другими процессами. Тот, кто породил, называется родителем или родительским процессом. А тот, кого породили, называется потомком или дочерним процессом. Все как в жизни :-)

Нетрудно догадаться, что такие пары "родитель-потомок" образуют иерархию процессов или дерево процессов. Любая иерархия имеет верхушку. В иерархии процессов Linux в роли верхушки выступает системный процесс init, который запускается ядром при загрузке. init всегда имеет PID, равный единице. Идентификатор процесса не может равняться нулю. Нулевой идентификатор считается несуществующим.

К каждому процессу привязывается не только собственный идентификатор, но и идентификатор родительского процесса. Иначе говоря, любой процесс всегда "знает" своего родителя. Идентификатор родительского процесса обозначают PPID (Parent Process IDentifier). Команда ps -fe показывает, что у init нулевой, то бишь не существующий в системе PPID; это единственное исключение. У всех других процессов PID != PPID != 0. Опция -f команды ps позволяет выводить не только собственные идентификаторы, но и идентификаторы родителей. И еще: у одного процесса может быть только один родитель и сколько угодно потомков.

3.4. Гонка за выживание

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

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

В нашей программе используются две функции: getpid() и getppid(). Первая возвращает идентификатор текущего процесса (запущенная программа), а вторая функция возвращает идентификатор родителя. Родителем является командный интерпретатор, который при получении команды ./pids порождает новый процесс и запускает в нем программу pids, которую мы написали.

Обратите внимание, что в качестве возвращаемого значения используется тип pid_t. На архитектуре IA-32 (32-разрядная Intel-архитектура, которая у большинства из нас) этот тип совпадает с типом int. Однако если вы хотите, чтобы ваша программа запускалась на любой архитектуре, пользуйтесь типом pid_t. К тому же использование типа pid_t во многом избавляет от путаницы в больших программах.

На сегодня все. Все комментарии и вопросы посылайте в форум.

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

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

В избранное