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

  Опросы
  Статьи

Электронный документооборот  

5 способов повысить безопасность электронной подписи

Область применения технологий электронной подписи с каждым годом расширяется. Все больше задач

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

Рынок труда  

Системные администраторы по-прежнему востребованы и незаменимы

Системные администраторы, практически, есть везде. Порой их не видно и не слышно,

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

Учебные центры  

Карьерные мечты нужно воплощать! А мы поможем

Школа Bell Integrator открывает свои двери для всех, кто хочет освоить перспективную

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

Гость номера  

Дмитрий Галов: «Нельзя сказать, что люди становятся доверчивее, скорее эволюционирует ландшафт киберугроз»

Использование мобильных устройств растет. А вместе с ними быстро растет количество мобильных

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

Прошу слова  

Твердая рука в бархатной перчатке: принципы soft skills

Лауреат Нобелевской премии, специалист по рынку труда, профессор Лондонской школы экономики Кристофер

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

1001 и 1 книга  
19.03.2018г.
Просмотров: 9943
Комментарии: 0
Потоковая обработка данных

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

19.03.2018г.
Просмотров: 8154
Комментарии: 0
Релевантный поиск с использованием Elasticsearch и Solr

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

19.03.2018г.
Просмотров: 8259
Комментарии: 0
Конкурентное программирование на SCALA

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

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

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

12.03.2018г.
Просмотров: 5910
Комментарии: 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-41
Fax: (499) 277-12-45
E-mail: sa@samag.ru