#c #c #fork
#c #c #fork
Вопрос:
Есть много вопросов fork()
, но я немного запутался в этом коде.Я анализирую код на c в том смысле, что у меня есть эта функция.
int daemon(int nochdir, int noclose)
{
switch (fork())
{
case 0: break;
case -1: return -1;
default: _exit(0); /* exit the original process */
}
if (setsid() < 0) /* shoudn't fail */
return -1;
/* dyke out this switch if you want to acquire a control tty in */
/* the future -- not normally advisable for daemons */
printf("Starting %s [ OK ]n",AGENT_NAME);
switch (fork())
{
case 0: break;
case -1: return -1;
default: _exit(0);
}
if (!nochdir)
{
chdir("/");
}
if (!noclose)
{
dup(0);
dup(1);
}
return 0;
}
Таким образом, форк создаст точную копию кода, из которого fork()
был вызван. так что,
- Выполняется ли переключение дважды или один раз?
- Если дважды, то в переключателе, что, если дочерний элемент выполняется первым? Будет ли он просто сломан или перейдет к другим заявлениям?
- Что делать, если родитель выполняет? будет ли основной процесс завершен, а дочерний процесс продолжится?
Редактировать: Таким образом, переключатель также будет выполняться дважды — один раз с родительским и один раз с дочерним. и ведет себя в зависимости от возвращаемых значений.
И последнее: демон — это предопределенная функция, и он был переопределен и использован как демон, созданный пользователем. Как он создаст демонический процесс и что
`if (!nochdir)
{
chdir("/");
}`
и
if (!noclose)
{
dup(0);
dup(1);
}
Я вызываю эту функцию следующим образом.
if (daemon(0, 0) < 0)
{
printf("Starting %s [ Failed ]n",AGENT_NAME);
exit(2);
}
Ответ №1:
Выполняется ли switch дважды или один раз?
Говорят, что fork — это функция, которая вызывается один раз, но возвращает дважды, то есть один раз в каждом процессе: один раз в родительском и один раз в дочернем.
человек :
При успешном выполнении PID дочернего процесса возвращается в родительском процессе, а 0 возвращается в дочернем. При сбое в родительском процессе возвращается -1, дочерний процесс не создается, и значение errno устанавливается соответствующим образом
Он может вернуться только один раз (-1): только в родительском, если дочерний элемент не был создан. Он всегда возвращается в родительском (-1 при ошибке, > 0 при успешном выполнении).
Если дважды, то в коммутаторе, что, если дочерний элемент выполняется первым? Будет ли это просто прерываться или переходить к другим операторам?
Неизвестно, дочерний или родительский элемент возвращается первым. После fork() все сегменты памяти копируются в дочерние, но он продолжается с правильным значением 0, возвращенным из fork() . Родительский элемент продолжает работу с pid дочернего элемента. Вы используете возвращаемое значение fork в коде, чтобы определить, являетесь ли вы дочерним или родительским. Возможно, это станет более понятным, если вы напишете код таким образом
int daemon( int nochdir, int noclose)
{
pid_t pid; /* to drive logic in the code */
if ( ( pid = Fork()) < 0) /* fork and remember actual value returned to pid */
return -1;
if( pid > 0)
_exit(0); /* exit the original process */
// here pid is 0, i.e. the child
Что, если родительский элемент выполняется? будет ли основной процесс завершен, а
дочерний процесс продолжится?
Что, если родительский exit() вызывается перед любыми дочерними инструкциями? Тогда да, родительский завершится, дочерний будет действовать самостоятельно. И родительский, и дочерний процессы имеют одинаковые сегменты кода, но выполняются независимо друг от друга (если вы не добавили некоторую синхронизацию).
Ответ №2:
Да, когда родительский процесс выполняется, он будет продолжаться в случае по умолчанию:, поскольку коммутатор вернет идентификатор дочернего процесса.
Общепринятое мнение о том, что fork() — это функция, которая вызывается один раз и возвращает два раза, немного запутывает, поскольку она возвращает только один раз в каждом пространстве процесса. Вопрос в том, был ли создан дочерний элемент или нет, который определяет, какой из двух способов возвращает родительский элемент. Родительский элемент никогда не получает результат ‘0’ от fork(), только либо -1, либо> 0. Дочерний элемент всегда (если вообще) получает ноль.
Если дочерний элемент не был создан, то fork() никогда не возвращается в пространство процесса.
Комментарии:
1.Когда дочерний элемент не был создан,
fork
возвращает значение -1. Поэтомуfork
всегда возвращается в «родительском», и если был создан дочерний элемент, он также вернется туда.2. Да, это то, что я сказал. «Родительский элемент никогда не получает результат ‘0’… только либо -1, либо> 0.»
3. Тогда я не понимаю, что вы имеете в виду, говоря «Если дочерний элемент не был создан, то fork() никогда не возвращается в свое пространство процессов».
4. Я имею в виду, что если дочерний элемент не был создан, нет дочернего пространства процесса (контекста памяти, стека), и поэтому в несуществующем дочернем элементе нет «возврата».
Ответ №3:
- Если нет ошибки,
fork
будет возвращен дважды: один раз в родительском процессе и один раз в дочернем процессе.fork
создает копию текущего процесса, затем продолжает выполнение в обоих процессах, и вы можете определить по возвращаемому значению. Обратите внимание, что копия (дочерняя) не является «идеальной» копией: например, в дочернем потоке все потоки завершаются, кроме одного выполняемогоfork
. Точное поведение немного сложное. - Не указано, родительский или дочерний процесс продолжает выполнение первым. Это зависит от вашей операционной системы и может даже быть совершенно случайным для вашей операционной системы. Поскольку это два отдельных процесса (которые запускают один и тот же код), порядок не имеет значения. Родительский процесс получит возвращаемое значение> 0 (или -1 при ошибке) и, таким образом, выполнит
default:
метку. Дочерний процесс получит возвращаемое значение 0 и, таким образом, выполнитcase 0:
метку. Это возвращаемое значение fork — это то, как родительский процесс знает, что он родительский, а дочерний процесс — что он дочерний (дочерний процесс может запрашивать свой собственный PID, используяgetpid(2)
и PID своего родителя, используяgetppid(2)
). - Да, родительский элемент запускается в
default:
метку и выполняется_exit
, завершая работу. Дочерний элемент продолжит выполнение (обратите внимание, что этоsetsid()
очень важно; без этого дочерний элемент не будет продолжать выполняться, если завершится сеанс оболочки вашего родительского элемента). Это обычный шаблон для создания демона: когда вы запускаете программу, она порождает фактическую основную программу (демон) посредством разветвления, а затем завершает работу. Например, в командной оболочке вы увидите, что программа быстро завершается, но при входеps
вы можете увидеть, что существует процесс с тем же именем (ваш демон).
Комментарии:
1. THNQ, поэтому переключатель будет выполняться дважды.
2. Да, но в двух отдельных процессах: каждый процесс выполняет только одну метку переключателя.