fork () внутри fork () - PullRequest
       10

fork () внутри fork ()

1 голос
/ 08 марта 2010

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

global variable i;

SIGCHLD handler function()
{
  i--;
}

handle()
{
  fork() --> FORK2
}

main()
{
  while(1)
  {
     if(i<5)
     {
        i++;
        if( (fpid=fork())==0) --> FORK1
           handle()
        else (fpid>0)
           .....
     }
  }
}

Можно ли как-то отличить дочерние процессы, созданные FORK1 и FORK2? потому что я пытаюсь уменьшить значение глобальной переменной 'i' в функции обработчика SIGCHLD, и оно должно уменьшаться только для процессов, созданных FORK1 ..

Я попытался использовать массив и сохранить идентификатор процесса дочерних процессов, созданных FORK1, и это делается родительским процессом. Я уменьшу значение 'i' только в том случае, если идентификатор массива мертвого потомка находится в массиве ...

Но я столкнулся с проблемой следующего сценария

child1 , parent1, child1 убит , child2 , child2 убит , parent2

Incase child1, так как он убит после parent1, массив обновлен должным образом.

Но что в случае child2, который уничтожается до того, как его значение pid обновляется parent2 в массиве? Внутри функции обработчика сигнала SIGCHLD, так как значение PID child2 отсутствует в массиве, значение 'i' не уменьшается соответственно ..

Так есть ли лучшее решение для этой проблемы ??

Ответы [ 3 ]

2 голосов
/ 08 марта 2010

Поскольку вы уже сохраняете список PID, для которых вы хотите уменьшить значение i в обработчике SIGCHLD, часть, которая может вас отключить, получает дополнительный SIGCHLD при обновлении список.

Вы можете замаскировать / заблокировать дополнительные SIGCHLD сигналы во время выполнения обработчика сигналов, используя sigprocmask(). Это должно предоставить вам достаточно времени для обновления массива / списка идентификаторов процессов, не беспокоясь о получении другого SIGCHLD. После завершения процедуры обработки сигнала заблокированная маска должна быть возвращена к своему первоначальному значению.

Попробуйте добавить в обработчик SIGCHLD что-то похожее на следующее:

sigset_t mask;
sigset_t orig_mask;

sigemptyset (&mask);
sigaddset (&mask, SIGCHLD);

/* temporarily mask/block SIGCHLD signals and save original mask */
if (sigprocmask(SIG_BLOCK, &mask, &orig_mask) < 0) {
    perror ("sigprocmask - %s",  strerror(errno));
}

/* process SIGCHLD via waitpid() and update PID list as necessary */
...

/* restore original mask */ 
if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0) {
    perror ("sigprocmask - %s", strerror(errno));
}

Обновление

После повторного изучения вашего вопроса я вижу, что у вас есть условие гонки, в котором дочерний процесс завершается до того, как родительский процесс может добавить свой PID в список.

Одним из возможных решений по-прежнему является использование sigprocmask() для блокировки сигнала SIGCHLD во время критической секции. В этом случае вам потребуется заблокировать сигнал SIGCHLD перед вызовом fork() и разблокировать его в родительском коде после добавления PID в список. Если ребенок умирает, обработчик сигнала будет вызван после того, как вы разблокируете сигнал, и это должно гарантировать, что PID находится в списке.

0 голосов
/ 08 марта 2010

Если я хорошо понимаю, вас может заинтересовать waitpid() системный вызов. Это позволяет вам ждать конкретного ребенка (с учетом pid). Поэтому, если вы будете отслеживать pid, созданный fork1 и fork2, вы сможете уменьшить значение переменной i только в случае смерти ребенка из fork1.

0 голосов
/ 08 марта 2010

использование:

getppid() function . 
...