Что такое форк линукс

Что такое форк линукс

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

pid_t является примитивным типом данных, который определяет идентификатор процесса или группы процессов. При вызове fork() порождается новый процесс (процесс-потомок), который почти идентичен порождающему процессу-родителю. Процесс-потомок наследует следующие признаки родителя:

  • сегменты кода, данных и стека программы;
  • таблицу файлов, в которой находятся состояния флагов дескрипторов файла, указывающие, читается ли файл или пишется. Кроме того, в таблице файлов содержится текущая позиция указателя записи-чтения;
  • рабочий и корневой каталоги;
  • реальный и эффективный номер пользователя и номер группы;
  • приоритеты процесса (администратор может изменить их через nice );
  • контрольный терминал;
  • маску сигналов;
  • ограничения по ресурсам;
  • сведения о среде выполнения;
  • разделяемые сегменты памяти.

Потомок не наследует от родителя следующих признаков:

  • идентификатора процесса (PID, PPID);
  • израсходованного времени ЦП (оно обнуляется);
  • сигналов процесса-родителя, требующих ответа;
  • блокированных файлов (record locking).

При вызове fork() возникают два полностью идентичных процесса. Весь код после fork() выполняется дважды, как в процессе-потомке, так и в процессе-родителе.

Процесс-потомок и процесс-родитель получают разные коды возврата после вызова fork() . Процесс-родитель получает идентификатор (PID) потомка. Если это значение будет отрицательным, следовательно при порождении процесса произошла ошибка. Процесс-потомок получает в качестве кода возврата значение 0, если вызов fork() оказался успешным.

Таким образом, можно проверить, был ли создан новый процесс:

Пример порождения процесса через fork() приведен ниже:

Когда потомок вызывает exit() , код возврата передается родителю, который ожидает его, вызывая wait() . WEXITSTATUS() представляет собой макрос, который получает фактический код возврата потомка из вызова wait() .

Функция wait() ждет завершения первого из всех возможных потомков родительского процесса. Иногда необходимо точно определить, какой из потомков должен завершиться. Для этого используется вызов waitpid() с соответствующим PID потомка в качестве аргумента. Еще один момент, на который следует обратить внимание при анализе примера, это то, что и родитель, и потомок используют переменную rv . Это не означает, что переменная разделена между процессами. Каждый процесс содержит собственные копии всех переменных.

Рассмотрим следующий пример:

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

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

Источник

Что такое форк линукс

Дочерний и родительский процессы находятся в отдельных пространствах памяти. Сразу после fork() эти пространства имеют одинаковое содержимое. Запись в память, отображение файлов (mmap(2)) и снятие отображения (munmap(2)), выполненных в одном процессе, ничего не изменяет в другом.

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

* Потомок имеет свой уникальный идентификатор процесса, и этот PID (идентификатор процесса) не совпадает ни с одним существующим идентификатором группы процессов (setpgid(2)). * Идентификатор родительского процесса у потомка равен идентификатору родительского процесса. * Потомок не наследует блокировки памяти родителя (mlock(2), mlockall(2)). * Счётчики использования ресурсов (getrusage(2)) и времени ЦП у потомка сброшены в 0. * Набор ожидающих сигналов потомка изначально пуст (sigpending(2)). * Потомок не наследует значения семафоров родителя (semop(2)). * Потомок не наследует связанные с процессом блокировки родителя (fcntl(2)) (с другой стороны, он наследует блокировки файловых описаний fcntl(2) и блокировки flock(2)). * Потомок не наследует таймеры родителя (setitimer(2), alarm(2), timer_create(2)). * Потомок не наследует ожидающие выполнения операции асинхронного ввода-вывода (aio_read(3), aio_write(3)) и контексты асинхронного ввода-вывода родителя (см. io_setup(2)).

Все перечисленные атрибуты указаны в POSIX.1. Родитель и потомок также отличаются по следующим атрибутам процесса, которые есть только в Linux:

* Потомок не наследует уведомления об изменении каталога (dnotify) родителя (смотрите описание F_NOTIFY в fcntl(2)). * Настройка PR_SET_PDEATHSIG у prctl(2) сбрасывается, и поэтому потомок не принимает сигнал о завершении работы родителя. * Резервное значение по умолчанию устанавливается равным родительскому текущему резервному значению таймера. Смотрите описание PR_SET_TIMERSLACK в prctl(2). * Отображение памяти, помеченное с помощью флага MADV_DONTFORK через madvise(2), при fork() не наследуется. * Сигнал завершения работы потомка всегда SIGCHLD (см. clone(2)). * Биты прав доступа к порту, установленные с помощью ioperm(2), не наследуются потомком; потомок должен установить все нужные ему биты с помощью ioperm(2).

Также стоит учитывать следующее:

* Процесс потомка создаётся с одиночной нитью — той, которая вызвала fork(). Всё виртуальное адресное пространство родителя копируется в потомок, включая состояние мьютексов, условных переменных и других объектов pthreads; в случае проблем с этим может помочь pthread_atfork(3). * В многонитивой программе после fork(2) потомок может безопасно вызывать только безопасные-асинхронные-сигнальные функции (смотрите signal(7)) до тех пор, пока не вызовет execve(2). * Потомок наследует копии набора открытых файловых дескрипторов родителя. Каждый файловый дескриптор в потомке ссылается на то же описание файла что и родитель (смотрите open(2)). Это означает, что два файловых дескриптора совместно используют флаги состояния открытого файла, текущее смещение файла и атрибуты ввода-вывода, управляемые сигналами (смотрите описание F_SETOWN и F_SETSIG в fcntl(2)). * Потомок наследует копии набора файловых дескрипторов открытых очередей сообщений родителя (смотрите mq_overview(7)). Каждый файловый дескриптор в потомке ссылается на то же описание открытой очереди сообщений что и родитель. Это означает, что два файловых дескриптора совместно используют флаги (mq_flags). * Потомок наследует копии набора потоков открытых каталогов родителя (смотрите opendir(3)). В POSIX.1 сказано, что соответствующие потоки каталогов в родителе и потомке могут совместно использовать позицию в потоке каталога; в Linux/glibc они не могут этого делать.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

ОШИБКИ

Возникло системного ограничение на количество нитей. Есть несколько ограничений, которые могут вызвать эту ошибку: был достигнут мягкий ограничитель RLIMIT_NPROC (задаётся с помощью setrlimit(2)), который ограничивает количество процессов и ните для реального ID пользователя; был достигнут ядерный системный ограничитель на количество процессов и нитей, /proc/sys/kernel/threads-max (смотрите proc(5)); был достигнуто максимальное количество PID, /proc/sys/kernel/pid_max (смотрите proc(5)).

EAGAIN Вызывающий работает по алгоритму планирования SCHED_DEADLINE и у него не установлен флаг сброса-при-fork (reset-on-fork). Смотрите sched(7). ENOMEM Вызов fork() завершился с ошибкой из-за невозможности разместить необходимые структуры ядра, потому что слишком мало памяти. ENOSYS Вызов fork() не поддерживается на этой платформе (например, из-за того, что аппаратное обеспечение не содержит блока управления памятью (MMU)).

СООТВЕТСТВИЕ СТАНДАРТАМ

ЗАМЕЧАНИЯ

В Linux, fork() реализован с помощью «копирования страниц при записи» (copy-on-write, COW), поэтому расходы на вызов состоят из времени и памяти, требуемой на копирование страничных таблиц родителя и создания уникальной структуры, описывающей задачу.

Источник

О дистрибутивах Linux. Клоны, форки и прочие ремиксы

Генеалогическое древо дистрибутивов Linux больше всего напоминает баобаб, оплетённый лианами: от одного ствола отходят ветви разного размера и свойств, да ещё и прикрытые компонентами, не всегда связанными генетически с данной ветвью. И чтобы разобраться в этом хитросплетении, перво-наперво не худо бы определиться с терминологией. Каковая достаточно неоднозначна.

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

Начнём с того, что все ныне живущие и развивающиеся дистрибутивы прямо (то есть путём наследования кода) или косвенно (посредством наследования идей) происходят от трёх первопредков — назовём их историческими предшественниками. Это Slackware, Debian, Red Hat. Которые, конечно, сами много унаследовали от дистрибутивов, так сказать, доисторических, таких, как MCC Interim Linux, TAMU и особенно SLS, однако в эти столь былинные времена углубляться не будем. А отметим зато, что на многие аспекты дистростроения в Linux оказали влияние и BSD-системы, особенно FreeBSD.

Традиционно к дистрибутивам, производным от трёх родительских, применяется обычно термин клон (clone). Он используется также и для вторых производных — например, ранний Mandrake, рассматривавшийся как клон Red Hat’а, в свою очередь стал основой для создания Altlinux. Однако такое значение термина клон представляется излишне широким.

Исходно термин клон (в биологии) применялся для именования организма, генетически идентичного исходному. Поэтому применительно к дистрибутивам клонами логично называть системы, полностью воспроизводящие функциональность исходного и основанного на той же кодовой базе. В этом смысле чистыми клонами ныне можно назвать, пожалуй, только такие дистрибутивы, как CentOS или Scientific Linux — результаты перекомпиляции исходных текстов Red Hat, сохраняющие с родителем почти полную бинарную совместимость — и это принципиальная позиция их разработчиков. Вероятно, к числу клонов можно отнести также ASPLinux, основанный на кодовой базе Fedora, однако в их совместимости я не очень уверен. Из дистрибутивов прежних лет типичным клоном Red Hat являлся Bkack Cat, создатели которого также ориентировались на полную совместимость с прототипом.

Клон может добавлять некоторую, обычно второстепенную, функциональность к родительской системе (например, Black Cat отличался от Red Hat в первую очередь улучшенной поддержкой кириллицы). Но это отнюдь не обязательно. Обычно возникновение клонов имеет под собой юридические или финансовые причины. Так, и Scientific Linux, и CentOS возникли после превращения Red Hat — дистрибутива общего назначения — в коммерческий RHEL (Red Hat Enterprise Linux), в бинарном виде распространяющийся исключительно вместе с платной коммерческой поддержкой. И ориентированы они были на тех пользователей, которые нуждались в исполнении приложений именно под RHEL, но не испытывали необходимости в его технической поддержке. Или просто не могли позволить себе таковую финансово. И потому сохранение совместимости с исходной системой является непременным условием дальнейшего их развития, а следовательно — видоопределяющим признаком.

От клонов следует отличать римейки (remake) — это продукты реанимации (или гальванизации) проектов, по тем или иным причинам прекративших своё развитие. Хотя чистые римейки в мире Linux — явление, похоже, крайне редкое. Пожалуй, на моей памяти была лишь пара таких случаев:

  1. приобретение фирмой Xandros дистрибутива Corel Linux, находившегося в состоянии клинической смерти;
  2. воссоздание заброшенного автором дистрибутива LRs GNU Linux под именем MyGeOs, каковой, впрочем, тоже скорее мёртв, чем жив.

В какой-то мере Gentoo можно считать римейком в Бозе почившего Stampede — на конец прошлого тысячелетия одного из самых прогрессивных и фронтирных дистрибутивов Linux. Однако здесь скорее приходится говорить об идейном влиянии, нежели собственно воскрешении усопшего.

К клонам идеологически близки порты (ports) — перенос инфраструктуры родительского дистрибутива на аппаратные платформы, им не поддерживаемые. исторически одним из первых портов был, вероятно, Yellow Dog, вариант Red Hat, адаптированный для работы на машинах с процессором PowerPC (а ныне также и Cell — например, на Sony PlayStation 3). Более современные примеры — адаптации Slackware для работы на 64-битных Intel-совместимых процессорах, такие, как SLAMD64 и BlueWhite64.

Разумеется, о бинарной совместимости портов с исходными системами говорить не приходится. Однако, поскольку главная их задача — поддержание привычной среды на ином «железе», они, как и клоны, должны воспроизводить инфраструктуру своих прародителей. Так, Yellow Dog вот уже более 10 лет развивается параллельно со своим первопредком, оставаясь, насколько мне известно, чрезвычайно на него похожим.

Порты на разные платформы могут развиваться и в рамках исходного дистрибутива — изначально или со временем. В последнем случае ранее созданные порты могут либо воссоединиться с генеральной линией, либо пойти пойти своим путём и обрести индивидуальность. Посмотрим, какова будет судьба 64-битных портов Slackware после обретения последней официальной поддержки архитектуры x86_64.

Напротив, форки (fork) — это отклонения от первоначальной генеральной линии развития дистрибутива, появляющиеся вследствие идеологических расхождений внутри команды разработчиков (или просто личных обстоятельств). Причемры форков особенно типичны для BSD-мира. Так, OpenBSD отделилась от NetBSD вследствие различия взглядов на вопросы безопасности, хотя, как говорят, именно в этом случае превалировали сугубо личные мотивы. А DragonFly BSD отпочковалась от FreeBSD в момент, когда генеральное развитие последней пошло по пути 5-й ветки.

В мире Linux чистых форков можно найти не так уж и много. Наиболее показательным будет, наверное, случай с Altlinux. Её предшественница, IPLabs Linux Team, на протяжении нескольких лет распространяла Mandrake Russian Edition — даже не клон, а почти точную копию исходной системы, дополненую в первую очередь локально зависимыми компонентами, которые активно включались в upstream основного дистрибутива. Пока в один прекрасный (или не очень?) момент представления о локализации разработчиков Mandrake и её русской инкарнации не разошлись настолько, что их совместное ведение кодового хозяйства оказалось невозможным. В результате появился дистрибутив Altlinux.

Первоначально как форк Debian зародилась и Ubuntu — исходно главной задачей этого дистрибутива была организация более короткого и планового релиз-цикла, при сохранении как общей кодовой базы, так и бинарной совместимости.

На обоих приведённых примерах хорошо видно, что состояние «чистого» форка является сугубо временным. Ориентируясь на ту же пользовательскую аудиторию, что и исходные системы, форки со временем неизбежно обрастают собственными особенностями, и о совместимости между ними говорить уже не приходится. Так, ныне взаимообмен пакетов и репозиториев между Mandriva и Altlinux практически невозможен. А использование пакетов Debian в Ubuntu (и наоборот) — в общем случае весьма проблематично. Хотя для пакетов с простыми зависимостями ещё удаётся. Однако рано или поздно судьба любого форка — превратиться в дериват.

Создатели дериватов, приняв за основу тот или иной дистрибутив, изначально ставят своей целью изменение его ориентации и, соответственно, функциональности. Исторически первым дериватом, безусловно, была Suse: взяв в качестве базовой системы конструктор Slackware, они предназначили его для корпоративного использования. И в этих целях снабдили средством автоматического конфигурирования — первым вариантом Yast’а.

В прямо противоположном направлении действовали разработчики Mandrake. Первоначально внешне это был весьма точный клон Red Hat. Однако если последний с самого своего зарождения ориентировался на корпоративное применение, то Mandrake резко сменил сексуальную ориентацию, первым, пожалуй, поставив во главу угла любовь к конечному, в том числе домашнему, пользователю — юзерофилию, пышным цветом распустившуюся в наши дни.

Промежуточную позицию занял Caldera Linux, позднее получивший имя OpenLinux. Будучи, как и Mandrake, изначально продуктом клонирования Red Hat, этот дистрибутив, с одной стороны, унаследовал от него приверженность корпоративным ценностям. А с другой — с симпатией относился и к конечным пользователям, правда, скорее не домашним, а офисным. Став в результате прототипом систем быстрого развёртнывания, идея которых наиболее полно воплотилась в Ubuntu и отчасти в Zenwalk’е.

Дериваты — наиболее многочисленная разновидность дистрибутивов. И со временем они настолько отходят от своих прародителей, что о их происхождении может напоминать разве что формат пакетов. А в случае с Suse и такой памяти не осталось…

Термины респин и ремикс вошли в обиход недавно, и ещё не вполне устоялись. Тем не менее, респином можно назвать нечто среднее между клоном и дериватом. С одной стороны, он также предполагает переориентацию сферы использования, с другой, как правило, сохраняет (или декларирует) совместимость с предком. К респинам можно отнести такое ответвление от Ubuntu, как Mint, снабжаемый «из коробки» мультимедийными кодеками, проприетарными драйверами и тому подобными не вполне свободными комопнентами.

Ремикс же — это чистая перекомплектация исходного дистрибутива под те или иные специальные задачи. Наибольшее их количество можно обнаружить также среди потомков Ubuntu. Одни из них — Kubuntu, Xubuntu, Edubuntu, Mythbuntu, — изначально имели или обрели со временем официальный статус, другие — Fluxbuntu, CrunchBang — ведут партизанские действия на этом фронте. Как ремикс позиционируется его майнтайнерами и проект Russian Fedora. В отличие от всех остальных производных дистрибутивов, ремиксы основываются не на кодовой базе исходной системы, а непосредственно на её репозиториях, перекомпиляция пакетов в них не предполагается в принципе.

Кроме дистрибутивов, место произрастания ног которых более или менее ясно, существуют и такие, которые невозможно произвести от какого-либо родителя по прямой линии. И которые контаминируют в себе особенности целого ряда систем. За отсутствием лучшего термина их можно так и назвать — контаминантами. Конечно, сама природа открытого софта способствует интенсивному взаимообмену идеями и приёмами их воплощения. Но для более некоторых дистрибутивов это заложено в самой их природе.

Самым ярким и известным примером дистрибутивов-контаминантов выступает, безусловно, Gentoo: в нём объединились идеи простоты, унаследованной от Slackware, оптимизации сборки под «железо», впервые реализованной в Stampede, и портообразная система сборки пакетов из исходников, разивающая принципы, заложенные в портах FreeBSD. Практически то же самое можно сказать и о таких дистрибутивах, как CRUX и Archlinux, в меньшей степени — о Sorcerer и его дериватах SourceMage и Lunar. Наконец, основоположник идеи сборки из исходников — дистрибутив RockLinux — также можно причислить к этой группе. Хотя единственное, что он в себе контаминировал — это идеи конструктивизма Linux’а додистрибутивной эры.

Источник

Читайте также:  Установка arch linux графическим установщиком
Оцените статью