системный вызов fork() внутри демона с использованием _exit()

#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() был вызван. так что,

  1. Выполняется ли переключение дважды или один раз?
  2. Если дважды, то в переключателе, что, если дочерний элемент выполняется первым? Будет ли он просто сломан или перейдет к другим заявлениям?
  3. Что делать, если родитель выполняет? будет ли основной процесс завершен, а дочерний процесс продолжится?

Редактировать: Таким образом, переключатель также будет выполняться дважды — один раз с родительским и один раз с дочерним. и ведет себя в зависимости от возвращаемых значений.

И последнее: демон — это предопределенная функция, и он был переопределен и использован как демон, созданный пользователем. Как он создаст демонический процесс и что

 `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() вызывается перед любыми дочерними инструкциями? Тогда да, родительский завершится, дочерний будет действовать самостоятельно. И родительский, и дочерний процессы имеют одинаковые сегменты кода, но выполняются независимо друг от друга (если вы не добавили некоторую синхронизацию).

http://linux.die.net/man/2/fork

Ответ №2:

Да, когда родительский процесс выполняется, он будет продолжаться в случае по умолчанию:, поскольку коммутатор вернет идентификатор дочернего процесса.

Общепринятое мнение о том, что fork() — это функция, которая вызывается один раз и возвращает два раза, немного запутывает, поскольку она возвращает только один раз в каждом пространстве процесса. Вопрос в том, был ли создан дочерний элемент или нет, который определяет, какой из двух способов возвращает родительский элемент. Родительский элемент никогда не получает результат ‘0’ от fork(), только либо -1, либо> 0. Дочерний элемент всегда (если вообще) получает ноль.

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

Комментарии:

1.Когда дочерний элемент не был создан, fork возвращает значение -1. Поэтому fork всегда возвращается в «родительском», и если был создан дочерний элемент, он также вернется туда.

2. Да, это то, что я сказал. «Родительский элемент никогда не получает результат ‘0’… только либо -1, либо> 0.»

3. Тогда я не понимаю, что вы имеете в виду, говоря «Если дочерний элемент не был создан, то fork() никогда не возвращается в свое пространство процессов».

4. Я имею в виду, что если дочерний элемент не был создан, нет дочернего пространства процесса (контекста памяти, стека), и поэтому в несуществующем дочернем элементе нет «возврата».

Ответ №3:

  1. Если нет ошибки, fork будет возвращен дважды: один раз в родительском процессе и один раз в дочернем процессе. fork создает копию текущего процесса, затем продолжает выполнение в обоих процессах, и вы можете определить по возвращаемому значению. Обратите внимание, что копия (дочерняя) не является «идеальной» копией: например, в дочернем потоке все потоки завершаются, кроме одного выполняемого fork . Точное поведение немного сложное.
  2. Не указано, родительский или дочерний процесс продолжает выполнение первым. Это зависит от вашей операционной системы и может даже быть совершенно случайным для вашей операционной системы. Поскольку это два отдельных процесса (которые запускают один и тот же код), порядок не имеет значения. Родительский процесс получит возвращаемое значение> 0 (или -1 при ошибке) и, таким образом, выполнит default: метку. Дочерний процесс получит возвращаемое значение 0 и, таким образом, выполнит case 0: метку. Это возвращаемое значение fork — это то, как родительский процесс знает, что он родительский, а дочерний процесс — что он дочерний (дочерний процесс может запрашивать свой собственный PID, используя getpid(2) и PID своего родителя, используя getppid(2) ).
  3. Да, родительский элемент запускается в default: метку и выполняется _exit , завершая работу. Дочерний элемент продолжит выполнение (обратите внимание, что это setsid() очень важно; без этого дочерний элемент не будет продолжать выполняться, если завершится сеанс оболочки вашего родительского элемента). Это обычный шаблон для создания демона: когда вы запускаете программу, она порождает фактическую основную программу (демон) посредством разветвления, а затем завершает работу. Например, в командной оболочке вы увидите, что программа быстро завершается, но при входе ps вы можете увидеть, что существует процесс с тем же именем (ваш демон).

Комментарии:

1. THNQ, поэтому переключатель будет выполняться дважды.

2. Да, но в двух отдельных процессах: каждый процесс выполняет только одну метку переключателя.