Если у меня есть процесс, и я его клонирую, PID такой же? - PullRequest
1 голос
/ 01 февраля 2011

Просто быстрый вопрос: если я клонирую процесс, PID клонированного процесса такой же, да?fork () создает дочерний процесс, в котором PID отличается, но все остальное остается тем же.Vfork () создает дочерний процесс с тем же PID.Exec работает, чтобы изменить процесс, выполняющийся в данный момент, на что-то другое.

Правильно ли я во всех этих утверждениях?

Ответы [ 5 ]

6 голосов
/ 01 февраля 2011

Ни fork(), ни vfork() не поддерживают одинаковый PID, хотя clone() может в одном сценарии (* a) .Все это разные способы достижения примерно одной и той же цели, создание отдельного потомка.

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

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

Сравните этот последний вариант с обычным копированием при записи, когда разделяется сама память (пока один изпроцессы записывают в него), но таблицы страниц, которые ссылаются на эту память, копируются.Другими словами, vfork() даже на более эффективнее, чем копирование при записи, по крайней мере для случая использования fork-follow-to-немедленный-exec.

Но в *В 1025 * большинстве случаев у ребенка другой идентификатор процесса, чем у родителя.


* a Ситуация становится сложной, когда вы clone() с CLONE_THREAD.На этом этапе процессы все еще имеют разные идентификаторы, но то, что составляет PID, начинает стираться.На самом глубоком уровне планировщик Linux не заботится о процессах, он планирует потоки.

Поток имеет идентификатор потока (TID) и идентификатор группы потоков (TGID).TGID - это то, что вы получаете от getpid().

Когда клонируется поток без CLONE_THREAD, ему присваивается новый TID, и ему также присваивается значение TGID (т.е., новый PID).

При CLONE_THREAD ему присваивается новый TID, но TGID (следовательно, и идентификатор процесса, о котором сообщается) остается тем же, что и родительский, поэтому у них действительно естьтот же PID.Тем не менее, они могут отличиться, получая TID от gettid().

Там происходит довольно много хитрости в отношении идентификаторов родительского процесса и доставки сигналов (как потокам в группе, так иSIGCHLD к родителю), все что можно посмотреть из справочной страницы clone() .

6 голосов
/ 01 февраля 2011

Не совсем. Если вы клонируете процесс с помощью fork / exec или vfork / exec, вы получите новый идентификатор процесса. fork() предоставит вам новый процесс с новым идентификатором процесса, а exec() заменит этот процесс новым процессом, но сохранив идентификатор процесса.

С здесь :

Функция vfork () отличается от fork () только в том, что дочерний процесс может поделиться кодом и данными с вызывающий процесс (родительский процесс). это значительно ускоряет клонирование с риском для целостности родительский процесс, если vfork () используется не по назначению.

3 голосов
/ 29 декабря 2013

Это заслуживает некоторого объяснения.И это просто, как дождь.

Учитывайте это.Программа должна делать некоторые вещи одновременно.Скажем, ваша программа печатает «Здравствуй, мир!» Каждую секунду, пока кто-нибудь не введет «Здравствуй, Майк», а затем каждую секунду печатает эту строку, ожидая, когда Джон изменит ее в будущем.

Как вы пишете это стандартным способом?В вашей программе, которая в основном выводит «привет», вы должны создать другую ветвь, которая ожидает ввода данных пользователем.

Вы создаете два процесса, один , выводящих эти строкии еще один, ожидающий пользовательский ввод.И только способ создания нового процесса в UNIX вызывал системный вызов fork (), например:

ret = fork();
if(ret > 0) /* parent, continue waiting */
else /* child */

Эта схема создала множество проблем.Пользователь вводит «Майк», но у вас нет простого способа передать эту строку родительскому процессу, чтобы он мог ее распечатать, потому что + каждый + процесс имеет свое собственное представление о памяти, которое не используется совместно с дочерним процессом.

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

Еще одна вещь, которую нужно разделить между дочерним элементома родителем являются, например, дескрипторы открытых файлов, дескрипторы разделяемой памяти, входные / выходные данные и т. д., которые также не сохранятся после fork ().

Итак.Сам вызов fork () должен был облегчить , включая общую память / сигналы и т. Д. Но как?Это была идея клона ().Этот вызов принимает флаг, указывающий , что именно вы бы поделились с ребенком.Например, память, обработчики сигналов и т. Д. И если вы вызовете это с флагом = 0, это будет идентично для fork (), с точностью до аргументов, которые они принимают.И когда создаются Pthread-файлы POSIX, этот флаг будет отражать атрибуты, которые вы указали в pthread_attr.

С точки зрения ядра, нет никакой разницы между процессами, созданными таким образом, и никакой особой семантики, чтобы различать "ПРОЦЕССЫ».Ядро даже не знает, что это за «поток», он создает новый процесс, но он просто объединяет его как ведущий к той группе процессов , у которой был родитель, который вызвал егозаботясь о том, что может сделать этот процесс.Таким образом, у вас есть разные процессы (которые имеют один и тот же pid), объединенные в группу процессов , каждый из которых назначен с другим «TID» (который начинается с PID родителя).Не забудьте объяснить, что clone () делает именно это.Вы можете передать это whaterver , в котором вы нуждаетесь (на самом деле старый вызов vfork () подойдет).Собираетесь ли вы поделиться памятью?Hanlers?Вы можете настроить все, просто убедитесь, что вы не конфликтуете с библиотекой pthreads, написанной сразу же после этого вызова.Важно то, что версия ядра довольно возмутительна, она ожидает, что будут переданы только 2 из 4 параметров, пользовательский стек и параметры.

1 голос
/ 01 февраля 2011

Поскольку PID является уникальным идентификатором процесса, невозможно иметь два разных процесса с одинаковым PID.

0 голосов
/ 01 февраля 2011

Потоки (которые имеют одинаковый видимый 'pid') реализуются с помощью вызова clone().Когда указан флаг CLONE_THREAD, новый процесс («поток») делится идентификатором группы потоков (TGID) со своим процессом-создателем.getpid фактически возвращает TGID.

Подробнее см. Справочную страницу клона .

Таким образом, реальный PID, видимый ядром, всегда отличается.Видимый PID одинаков для потоков.

...