2010-03-07 6 views
6

Я читал про вилку и, насколько я понимаю, процесс клонирован, но какой процесс? Сам сценарий или процесс, который запустил скрипт?Что происходит, когда процесс разветвляется?

Например:

Я бегу rTorrent на моей машине, и когда поток завершается, я скрипт работать против него. Этот сценарий извлекает данные из Интернета, поэтому требуется несколько секунд. За это время мой rtorrent-процесс заморожен. Так что я сделал вилку сценария с помощью следующей

my $pid = fork(); 
if ($pid == 0) { blah blah blah; exit 0; } 

Если я запускаю этот скрипт из CLI, он возвращается к оболочке в течение одной секунды, пока он работает в фоновом режиме, точно так, как я предполагал. Однако, когда я запускаю его из rTorrent, он кажется еще медленнее, чем раньше. Итак, что именно было раздвоено? Был ли процесс rtorrent клонирован сам, и мой скрипт работал в этом, или мой скрипт был клонирован сам? Я надеюсь в этом есть смысл.

+1

Пожалуйста, начните с публикации рабочего фрагмента perl. –

+2

Попробуйте запустить rTorrent в strace и посмотрите, что он блокирует, когда работает ваш скрипт. Это может дать ключ. Я думал, что это может быть ждать() в процессе внука, но похоже, что поведение на самом деле невозможно, используя традиционные системные вызовы. – jdizzle

ответ

2

Чтобы ответить на номинальный вопрос, поскольку вы прокомментировали, что принятый ответ не делает этого, fork влияет на процесс, в котором он вызывается.В вашем примере rTorrent нерест процесса Perl, который затем вызывает fork, это процесс Perl, который дублируется, поскольку это был процесс Perl, который назывался fork.

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

+2

Кроме того, открывая возможность для множества шуток: «Эй, ты! «Нет, вилка ты!» – Ether

6

fork() функция возвращает ДВАЖДЫ! Однажды в родительском процессе и один раз в дочернем процессе. В общем, оба процесса являются ИДЕНТИЧНЫми во всех отношениях, как будто EACH только что вернулся с fork(). Единственное различие заключается в том, что в одном возвращаемое значение от fork() равно 0, а в другом оно отличное от нуля (PID дочернего процесса).

Так что независимо от того, какой процесс выполнял ваш скрипт Perl (если он встроенный интерпретатор Perl внутри rTorrent, а затем rTorrent был бы процессом), он был бы продублирован точно в том месте, где произошло событие fork().

+0

Я не думаю, что это действительно касается его вопроса ... – jdizzle

+2

@jdizzle - Наверное, потому что вопрос не имеет большого смысла, потому что «кто-то» не понимает процесс и разветвляет идеи. Объяснение некоторых фактов может помочь :) – viraptor

+1

@ viraptor - Я чувствую, что у кого-то есть достаточно хорошее представление о вилке() ing. Вопрос действительно в реализации rTorrent. – jdizzle

3

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

+0

Meh. Это не значит, что это конец света fork() в perl на машине конечного пользователя. Я согласен с тем, что часто использовать плохую практику часто (так как это зрелая точка для узкого места). – jdizzle

+0

Если это плохая практика, существует ли альтернативный метод предотвращения блокировки? – somebody

2

Мой совет будет «не делай этого».

Если интерпретатор Perl встроен в процесс rtorrent, вы почти наверняка разветвили весь процесс rtorrent, эффекты которого, вероятно, в лучшем случае не определены. Как правило, плохой идеей играть с материалом уровня процесса во встроенном интерпретаторе, независимо от языка.

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

+0

Насколько распространено это отношение к интерпретатору perl? Разве это не было бы намного более практичным (и безопасным) для системных() подобных вызовов? – jdizzle

+0

Правда, что вызов 'fork()' в многопоточной программе вызывает проблемы. Если вы ограничиваете то, что происходит в дочернем процессе, это не так уж плохо. Например, не вызывайте ничего, что необходимо для блокировки пользовательского режима. Но типичное использование следующих 'fork()' с 'dup2()', 'close()', 'execve()' и т. Д. Должно быть безопасным. – asveikau

+0

@jdizzle: связь с внешним интерпретатором, Perl или иным образом, очень распространена, но не совсем ясно из вопроса, так или нет с этой программой. Однако при повторном чтении вы можете быть прав, что система() используется. –

4

Я считаю, что нашел проблему, просмотрев источник rTorrent. Для некоторых процессов он будет читать весь вывод, отправленный на stdout, прежде чем продолжить. Если это происходит с вашим процессом, rTorrent блокируется, пока вы не закроете процесс stdout. Поскольку вы используете forking, ваш дочерний процесс имеет тот же stdout, что и родительский. Ваш родительский процесс выйдет, но канал остается открытым (потому что ваш дочерний процесс все еще запущен). Если вы сделали strace rTorrent, я бы поспорил, что он будет заблокирован при вызове read() во время выполнения вашей команды.

Попробуйте закрыть/перенаправить stdout в свой скрипт perl перед fork().

+0

Решает проблему, но не отвечает на номинальный вопрос. Я хотел бы, что. – darch

+0

@ darch - название вопроса действительно актуально для проблемы, которую кто-то пытается решить. – jdizzle

+0

Я нашел это очень полезным, поэтому спасибо, что поставил его, хотя он «не ответил на номинальный вопрос», @jdizzle :) –

1

Когда мы создаем процесс с использованием fork, дочерний процесс будет иметь копию адресного пространства. Так же ребенок также может использовать адресное пространство. И он также может получить доступ к файлам, которые открывается родителем. Мы можем иметь контроль над ребенком. Чтобы получить полный статус ребенка, мы можем использовать wait.

Смежные вопросы