Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
219
Добавлен:
02.05.2014
Размер:
2.83 Mб
Скачать

12. Понятие суперпроцесса

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

13. Потоки

Процессы в системе

Рассказ о жизни процессов естественно начать с самого начала — с их появления на свет. Так вот, процессы размножаются... почкованием: системный вызов Linux, создающий новый процесс, называется clone, а дочерний процесс представляет собой почти точную копию родительского. Только далее он выполняет назначенную ему функцию, а исходный процесс — то, что написано в программе после вызова clone. Потом отличий может стать больше, так что пути-дороги процессов способны разойтись достаточно далеко. Но если нам нужно этому воспрепятствовать, вызов clone позволит задать флаги, указывающие, что порожденный процесс будет иметь со своим предком общие:

  • адресное пространство (CLONE_VM);

  • информацию о файловой системе (CLONE_FS): корневой и текущий каталоги, а также umask;

  • таблицу открытых файлов (CLONE_FILES);

  • таблицу обработчиков сигналов (CLONE_SIGHAND);

  • родителя (CLONE_PARENT) — конечно, в этом случае будет порожден не дочерний, а сестринский процесс.

Нить и задача

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

Помимо процессов описанного выше вида бывают еще «ущербные», порождаемые с помощью функции kernel_thread для внутренних системных нужд. У них нет параметров командной строки, как правило, они не имеют открытых файлов и т. д. Поскольку, несмотря на свою ущербность, эти процессы все равно фигурируют в списке задач, в литературе иногда различают полноценные процессы, порожденные из «пространства пользователя» (userspace), и задачи, т. е. все процессы, включая внутренние процессы ядра.

Процесс и программа

Вы скажете: все это замечательно, но если новый процесс — всегда копия существующего, то каким образом в системе ухитряются работать разные программы? И откуда берется самая первая из них?

Процессы, выполняющие разные программы, образуются благодаря применению имеющихся в стандартной библиотеке Unix функций «семейства exec»: execl, execlp, execle, execv, execve, execvp. Эти функции отличаются форматом вызова, но в конечном итоге делают одну и ту же вещь: замещают внутри текущего процесса исполняемый код на код, содержащийся в указанном файле. Файл может быть не только двоичным исполняемым файлом Linux, но и скриптом командного интерпретатора, и двоичным файлом другого формата (например, классом java, исполняемым файлом DOS). В последнем случае способ его обработки определяется настраиваемым модулем ядра под названием binfmt_misc.

Таким образом, операция запуска программы, которая в DOS и Windows выполняется как единое целое, в Linux (и в Unix вообще) разделена на две: сначала производится запуск, а потом определяется, какая программа будет работать. Есть ли в этом смысл и не слишком ли велики накладные расходы? Ведь создание копии процесса предполагает копирование весьма значительного объема информации.

Смысл в данном подходе определенно есть. Очень часто программа должна совершить некоторые действия еще до того, как начнется собственно ее выполнение. Скажем, в разбиравшемся выше примере мы запускали две программы, передающие друг другу данные через неименованный канал. Такие каналы создаются системным вызовом pipe; он возвращает пару файловых дескрипторов, с которыми в нашем случае оказались связаны стандартный поток ввода (stdin) программы wc и стандартный поток вывода (stdout) программы dd. Стандартный вывод wc (как, кстати, и стандартный ввод dd, хотя он никак не использовался) связывался с терминалом, а кроме того, требовалось, чтобы командный интерпретатор после выполнения команды не потерял связь с терминалом. Как удалось этого добиться? Да очень просто: сначала были отпочкованы процессы, затем проделаны необходимые манипуляции с дескрипторами файлов и только после этого вызван exec.

Аналогичного результата (как показывает, в частности, пример Windows NT) можно было бы добиться и при запуске программы за один шаг, но более сложным путем. Что же касается накладных расходов, то они чаще всего оказываются пренебрежимо малыми: при создании копии процесса его индивидуальные данные физически никуда не копируются. Вместо этого используется техника, известная под названием copy-on-write (копирование при записи): страницы данных обоих процессов особым образом помечаются, и только тогда, когда один процесс пытается изменить содержимое какой-либо своей страницы, она дублируется.