форк 100 процессов одновременно и иногда некоторые процессы становятся зомби

Я пытаюсь запустить 100 процессов одновременно в следующем коде:

int cnt = 0;

void sig_handler(int signo) {
pid_t pid;
int stat;
pid = wait(&stat);
cout << "cnt:" << ++cnt << ", pid:" << pid << " signal:" << signo << endl;
}

int main() {
signal(SIGCHLD, sig_handler);
for (int i = 0; i < 100; ++i) {
if (fork() == 0) {
sleep(1);
exit(0);
}
}
printf("wait\n");
while (1);
}

Я ловлю SIGCHLD сигнал в sig_handlerрезультаты разные: иногда все процессы возвращаются нормально; иногда от 1 до 4 процессов становятся зомби.

[vinllen@my-host]$ ./a.out
wait
cnt:1, pid:4383 signal:17
cnt:2, pid:4384 signal:17
cnt:3, pid:4385 signal:17
cnt:4, pid:4386 signal:17
cnt:5, pid:4387 signal:17
…
cnt:94, pid:4476 signal:17
cnt:95, pid:4477 signal:17
cnt:96, pid:4478 signal:17
cnt:97, pid:4479 signal:17
cnt:98, pid:4480 signal:17

[vinllen@my-host ~]$ ps aux | grep a.out
Vinllen       4382 96.2  0.0  13896  1084 pts/8    R+   15:14   0:03 ./a.out
Vinllen       4481  0.0  0.0      0     0 pts/8    Z+   15:14   0:00 [a.out] <defunct>
Vinllen       4482  0.0  0.0      0     0 pts/8    Z+   15:14   0:00 [a.out] <defunct>
Vinllen       4493  0.0  0.0 105300   864 pts/9    S+   15:14   0:00 grep a.out

Я предполагаю, что причина в том, что несколько процессов одновременно завершают работу и что-то инициируют. Может ли кто-нибудь дать мне подробную причину и сказать, как решить эту проблему.

В моем понимании, двойная вилка и игнорирование SIGCHLD — два эффективных способа решения этой проблемы. Тем не менее, как решить в этом коде, что до сих пор вызывает wait,

2

Решение

Сигналы не поставлены в очередь. Если SIGCHLD повышен, пока один находится в состоянии ожидания (возможно, когда ваш код находится в write syscall), программа получит только одно уведомление.

Правильный способ сделать это — зациклить ваш обработчик до тех пор, пока не будут получены все готовые дочерние элементы:

void sig_handler(int signo) {
pid_t pid;
int stat;
while ((pid = waitpid(-1, &stat, WNOHANG) > 0)
if (WIFEXITED(stat))
{
// Don't actually do this: you should
// avoid buffered I/O in signal handlers.
std::cout << "count:" << ++cnt
<< ", pid:" << pid
<< " signal:" << signo
<< std::endl;
}
}

Как уже упоминалось в комментариях, вы должны придерживаться документированных асинхронно-безопасные функции в обработчиках сигналов. Буферизованный ввод / вывод (включая использование std::cout) может быть рискованным, так как обработчик сигнала может быть вызван, когда он манипулирует своими внутренними структурами. Лучший способ избежать проблем — ограничиться общением с основным кодом с помощью volatile sig_atomic_t переменные.

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]