«Убиваем» зомби::Журнал СА 1.2004
www.samag.ru
Журнал «БИТ. Бизнес&Информационные технологии»      
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
Журнал "Системный администратор"
Журнал «БИТ»
Подписка
Архив номеров
Где купить
Наука и технологии
Авторам
Рекламодателям
Контакты
   

  Опросы
1001 и 1 книга  
19.03.2018г.
Просмотров: 6981
Комментарии: 0
Машинное обучение с использованием библиотеки Н2О

 Читать далее...

12.03.2018г.
Просмотров: 7441
Комментарии: 0
Особенности киберпреступлений в России: инструменты нападения и защита информации

 Читать далее...

12.03.2018г.
Просмотров: 4847
Комментарии: 0
Глубокое обучение с точки зрения практика

 Читать далее...

12.03.2018г.
Просмотров: 3189
Комментарии: 0
Изучаем pandas

 Читать далее...

12.03.2018г.
Просмотров: 3987
Комментарии: 0
Программирование на языке Rust (Цветное издание)

 Читать далее...

19.12.2017г.
Просмотров: 3991
Комментарии: 0
Глубокое обучение

 Читать далее...

19.12.2017г.
Просмотров: 6487
Комментарии: 0
Анализ социальных медиа на Python

 Читать далее...

19.12.2017г.
Просмотров: 3340
Комментарии: 0
Основы блокчейна

 Читать далее...

19.12.2017г.
Просмотров: 3616
Комментарии: 0
Java 9. Полный обзор нововведений

 Читать далее...

16.02.2017г.
Просмотров: 7476
Комментарии: 0
Опоздавших не бывает, или книга о стеке

 Читать далее...

17.05.2016г.
Просмотров: 10844
Комментарии: 0
Теория вычислений для программистов

 Читать далее...

30.03.2015г.
Просмотров: 12551
Комментарии: 0
От математики к обобщенному программированию

 Читать далее...

18.02.2014г.
Просмотров: 14271
Комментарии: 0
Рецензия на книгу «Читаем Тьюринга»

 Читать далее...

13.02.2014г.
Просмотров: 9289
Комментарии: 0
Читайте, размышляйте, действуйте

 Читать далее...

12.02.2014г.
Просмотров: 7244
Комментарии: 0
Рисуем наши мысли

 Читать далее...

10.02.2014г.
Просмотров: 5540
Комментарии: 3
Страна в цифрах

 Читать далее...

18.12.2013г.
Просмотров: 4770
Комментарии: 0
Большие данные меняют нашу жизнь

 Читать далее...

18.12.2013г.
Просмотров: 3590
Комментарии: 0
Компьютерные технологии – корень зла для точки роста

 Читать далее...

04.12.2013г.
Просмотров: 3295
Комментарии: 0
Паутина в облаках

 Читать далее...

03.12.2013г.
Просмотров: 3526
Комментарии: 1
Рецензия на книгу «MongoDB в действии»

 Читать далее...

02.12.2013г.
Просмотров: 3181
Комментарии: 0
Не думай о минутах свысока

 Читать далее...

Друзья сайта  

 «Убиваем» зомби

Архив номеров / 2004 / Выпуск №1 (14) / «Убиваем» зомби

Рубрика: Программирование /  Анализ данных

АНДРЕЙ УВАРОВ

«Убиваем» зомби

Практически в любой *nix-подобной операционной системе существует такое понятие, как «зомби». В качестве примера возмём Linux (2.4.20). Зомби – это процесс, завершивший своё выполнение, но не удалённый. Зомби практически не занимают никаких ресурсов, но поскольку они являются процессами, то занимают место в proc. Как известно, количество процессов в системе ограничено, и если текущее количество процессов максимально, то операционная система отказывает нам в создании новых процессов, мотивируя это временным отсутствием ресурсов. Таким образом и рождается проблема с зомби: их возникает так много, что в системе больше не могут создаваться новые процессы. Но чаще зомби встречаются поодиночке. С зомби сталкивался практически каждый программист, а число программ, в которых были или есть проблемы с зомби, настолько велико, что перечислить их все не представляется возможным. Вот только некоторые из них: lynx, xchat, links, stunnel, galeon, xinetd.

Процесс становится зомби тогда, когда он уже завершился, а в его родительском процессе не была вызвана функция wait. Функции wait, wait3, wait4 и waitpid предназначены для получения родительским процессом кода завершения его потомка. В случае если потомок уже завершился, все системные ресурсы, занимаемые процессом, будут освобождены, а функция немедленно возвратит значение pid потомка.

Для начала попробуем просто создать процесс-потомок:

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>

int main(){
    // С этого места начинает своё выполнение потомок
    pid_t chld_PID= fork();
    // Если chld_PID == 0, то текущий процесс – потомок
    if(chld_PID!= 0){
           printf("I"m a parent ");
    }else{
           printf("I"m a child ");
 
    return 0;
}

Вызовом fork создаётся копия текущего процесса. Выполнение нового процесса начинается с того места, где был произведён вызов fork. В случае благополучного создания нового процесса родителю fork возвращает pid потомка, а потомку возвращается ноль (значение 0 не является pid самого потомка, в Linux не существует процессов с pid, равным 0, для получения идентификатора текущего процесса необходимо использовать getpid). Это необходимо для того, чтобы процесс мог определить, является ли он родителем или потомком. В случае ошибки новый процесс не создаётся и возвращается -1.

Разобравшись с вызовом fork, попробуем создать одного зомби:

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>

int main(){
    pid_t chld_PID= fork();
    if(chld_PID!= 0){
           printf("I"m a parent ");
           // Остановим выполнение родителя до ввода символа
           getchar();
    }else{
           printf("I"m a child ");
    }
    return 0;
}

Откомпилируем и выполним текущий пример. Для того чтобы «увидеть в глаза» нашего зомби, получим список процессов:

[dashin@dashin zombies]$ ps ax

  PID TTY      STAT   TIME COMMAND              
   1  ?        S      0:05 init                 
............................................... 
                                                
18730 pts/4    S      0:00 bash -rcfile .bashrc 
18767 pts/4    S      0:00 ./one_zomb           
18768 pts/4    Z      0:00 [one_zomb ]          
18864 pts/5    R      0:00 ps ax                

Значение поля STAT, равное Z, означает, что данный процесс и есть наш зомби. Но поодиночке зомби не страшны, поэтому модифицируем предыдущий пример:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

    int main(){
  pid_t our_child;
  while(our_child != -1){
      our_child= fork();
      if(our_child == 0){              
          return 0;
      }
  }
  getchar();
  return 0;
}

Итак, откомпилировав и выполнив текущий пример, мы получим максимальное количество процессов в системе. Если попробуем выполнить команду ps, то получим сообщение о невозможности выполнения нашей команды по известной нам причине (команда ps взята для примера, вызов практически любой команды будет завершён подобным образом).

[dashin@dashin  zombies]$ ps ax

bash: fork: Resource temporarily unavailable

Разобравшись с тем, что представляют собой зомби, стоит ознакомиться с некоторыми способами устранения создаваемой зомби проблемы.

Один из самых простых способов «убить» зомби – это «убить» их родителя. Если в системе «умирает» какой-либо процесс, то специальный демон init наследует всех потомков умершего процесса и удаляет их, если они уже завершили своё выполнение. Но у нас может не хватать прав на удаление родителя. Возможна ситуация, когда родитель выполняет какие-то необходимые нам действия, и, удалив его, можно потерять данные. Может быть множество причин, препятствующих этому способу. И нам останется только по очереди убивать всех зомби.

Очевидно, что лучше предотвратить зомби, нежели с ними бороться. Одним из решений является использование вышеупомянутой функции wait.

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
    
  
int main(){
  
   pid_t our_child;   
   our_child= fork();
   if(our_child == 0){
        return 0;
   }
   sleep(10);    
   wait();
   getchar();
   return 0;
}

Для наглядности этого примера выполним команду:

top -d 1

и параллельно выполним предварительно откомпилированный пример (см. рис.1).

Рисунок 1. Видимо, не только мы умеем порождать зомби

Рисунок 1. Видимо, не только мы умеем порождать зомби

Как и ожидалось, наш зомби, просуществовав около 10 секунд, будет удалён.

Учитывая то, что если дочерний процесс прерван или остановлен, он шлёт своему родителю сигнал SIGCHLD, тогда можно сделать у родителя обработчик этого сигнала и в нём вызывать wait.

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>

 
void killchld(){
   wait();
}
 
int main(){
   pid_t our_child;
   int i;
   signal(SIGCHLD, killchld);
   for(i=1;i< 0xFF;i++){
       our_child= fork();
       if(our_child == 0){            
          return 0;
       }
   }
   getchar();
   return 0;
}

В данном примере мы устанавливаем обработчик сигнала SIGCHLD вызовом signal. В качестве первого параметра signal имеет сигнал (точнее сказать – номер сигнала), который мы собираемся обрабатывать, а второй параметр – имя нашей функции-обработчика. Но здесь есть одна небольшая тонкость – если в качестве второго параметра установим SIG_IGN, то наши зомби будут умирать, но как сказано в man: «POSIX (3.3.1.3) не определяет, что случается при SIGCHLD, который установлен в SIG_IGN». То есть если у нас следующий пример будет работать в Linux – не значит, что он будет работать в BSD. Следовательно, таким способом пользоваться не рекомендуется.

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>

 
int main(){
   pid_t our_child;
   signal(SIGCHLD, SIG_IGN);   // Так делать не стоит
   int i;
   for(i=1;i< 0xFF;i++){
       our_child= fork();
       if(our_child == 0){            
          return 0;
       }
   }
   getchar();
   return 0;
}

Способ избежать зомби в большинстве случаев зависит от ситуации. Важно помнить, что зомби нужны забота и внимание. И только тогда они не будут вас беспокоить.


Комментарии отсутствуют

Добавить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-45
E-mail: sa@samag.ru