2010-10-03 1 views
4

Я создаю фоновые процессы в C, используя fork().Фоновый процесс выходит быстрее, чем я могу добавить его pid для управления

Когда я создал один из этих процессов, я добавляю его pid в массив, чтобы я мог отслеживать фоновые процессы.

pid = fork(); 

    if(pid == -1) 
    { 
     printf("error: fork()\n"); 
    } 
    else if(pid == 0) 
    { 
     execvp(*args, args); 
     exit(0); 
    } 
    else 
    { 
     // add process to tracking array 
     addBGroundProcess(pid, args[0]); 
    } 

У меня есть обработчик для пожинают зомби

void childHandler(int signum) 
{ 
    pid_t pid; 
    int status; 

    /* loop as long as there are children to process */ 
    while (1) { 

     /* get zombie pids */ 
     pid = waitpid(-1, &status, WNOHANG); 

     if (pid == -1) 
     { 
      if (errno == EINTR) 
      { 
       continue; 
      } 

      break; 
     } 
     else if (pid == 0) 
     { 
      break; 
     } 

     /* Remove this child from tracking array */ 
     if (pid != mainPid) 
      cleanUpChild(pid); 
    }  
} 

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

Я использую команды, такие как emacs &, которые не должны выходить немедленно.

Что мне не хватает?

Спасибо.

ответ

0

Ваш код просто улавливает выход дочернего процесса, который он сделал fork'ed, что не означает, что другой процесс не был предварительно спровоцирован этим ребенком. Я предполагаю, что emacs в вашем случае по какой-то причине делает другую fork(), а затем позволяет начальному процессу выйти (это будут демоны трюков).

Функция setsid() также может стоить взглянуть на нее, хотя не записывая код самостоятельно, чтобы проверить его. Я не уверен, что это актуально здесь.

+0

Чтобы быть ясным, вы говорите, что, поскольку я вызвал emacs & (с &), что Unix породит другого ребенка, чтобы выполнить фоновый процесс emacs, тем самым, заставив созданного мной ребенка умереть и поднять флаг SIGCHLD? –

+0

Ах .. Я пропустил «&». Казалось бы, это вероятная причина второй вилки. Хотя более конкретно, я думаю, что «&» может вызвать порождение оболочки, которая выполняет emacs и сразу же выходит. Имейте в виду, что это не в моей голове, поэтому я еще не сделал много, чтобы проверить это. –

+0

Если я не запускаю emacs & и вместо этого запускаю emacs, emacs открывается в текущем сеансе терминала. Это поведение я не хочу. Я действительно хочу выполнить команду (emacs, ls и т. Д.) В фоновом режиме и отслеживать эти процессы и очищать зомби по мере их возникновения. –

4

Вы правы, там есть состояние гонки. Я предлагаю вам заблокировать доставку SIGCHLD с помощью функции sigprocmask. Когда вы добавили новый PID в свою структуру данных, разблокируйте сигнал еще раз. Когда сигнал блокируется, если этот сигнал принят, ядро ​​помнит, что ему нужно передать этот сигнал, а когда сигнал разблокирован, он доставлен.

Вот что я имею в виду, а именно:

sigset_t mask, prevmask; 

//Initialize mask with just the SIGCHLD signal 
sigemptyset(&mask); 
sigaddset(&mask, SIGCHLD); 

sigprocmask(SIG_BLOCK, &mask, &prevmask); /*block SIGCHLD, get previous mask*/ 
pid = fork(); 

if(pid == -1) 
{ 
    printf("error: fork()\n"); 
} 
else if(pid == 0) 
{ 
    execvp(*args, args); 
    exit(0); 
} 
else 
{ 
    // add process to tracking array 
    addBGroundProcess(pid, args[0]); 

    // Unblock SIGCHLD again 
    sigprocmask(SIG_SETMASK, &prevmask, NULL); 
} 

Кроме того, я думаю, что есть вероятность того, что execvp может быть сбой. (Хорошо справиться с этим в целом, даже если это не происходит в этом случае.) Это зависит от того, как это реализовано, но я не думаю, что вам разрешено положить & в конце команды, чтобы получить его для запуска в фоновом режиме. Запуск emacs сам по себе, вероятно, то, что вы хотите в этом случае в любом случае, и положить & в конце командной строки - это функция, предоставляемая оболочкой.

Редактировать: Я видел ваши комментарии о том, как вы не хотите, чтобы emacs запускался в текущем сеансе терминала. Как вы хотите, чтобы он запускался, точно - в отдельном окне X11, возможно? Если это так, есть и другие способы достижения этого.

Довольно простой способ обработки execvp «s отказ должен сделать это:

execvp(*args, args); 
    perror("execvp failed"); 
    _exit(127); 
0

Вы не должны использовать оболочку с & для запуска фоновых процессов. Если вы это сделаете, они выйдут в роли внуков, которых вы не можете отслеживать и ждать. Вместо этого вам нужно либо подражать тому, что оболочка выполняет для запуска фоновых процессов в вашем собственном коде, либо, вероятно, будет работать так же, как закрыть терминал (или, скорее, stdin/out/err) и открыть /dev/null вместо его дочерних процессов поэтому они не пытаются писать на терминал или взять на себя управление им.

+0

Можете ли вы объяснить это дальше или привести пример? Я согласен, что выполнение с помощью & неверно, но я не хочу, чтобы команда использовала терминал. И я не хочу закрывать терминал. –

+0

Если вы не хотите, чтобы команда использовала терминал, почему бы вам не закрыть терминал? Вы закрываете его в процессе ** child **, а не в родительском. –

+0

Просто неверно общаться ... Я хочу закрыть терминал для дочернего процесса, так что его может использовать только процесс переднего плана (моя оболочка). –

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

  • Нет связанных вопросов^_^