Фоновый процесс завершается быстрее, чем я могу добавить его pid для управления - PullRequest
4 голосов
/ 03 октября 2010

Я создаю фоновые процессы в C с помощью fork ().

Когда я создал один из этих процессов, я добавляю его 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.1009 *

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

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

Спасибо.

Ответы [ 3 ]

4 голосов
/ 03 октября 2010

Вы правы, там есть состояние гонки.Я предлагаю вам заблокировать доставку 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 - сделать это:

    execvp(*args, args);
    perror("execvp failed");
    _exit(127);
0 голосов
/ 03 октября 2010

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

0 голосов
/ 03 октября 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...