Как склеить систему благодаря процессам?

#c #linux #process #fork

#c #linux #процесс #форк

Вопрос:

Общие сведения и пояснения о функционировании моей программы

Я написал программу, целью которой является создание процессов до тех пор, пока она больше не сможет этого делать (то есть: она должна склеить ОС и полностью заполнить таблицу процессов). Однако, когда ОС склеивается, появляется сообщение типа « fork больше не может быть сделано», и все процессы могут быть убиты конечным пользователем благодаря CTRL Z.

Моя программа содержит два важных процесса: основной, который создает второй. Первый называется «MAIN_P» в моем коде, а последний «P_ROOT». Цель P_ROOT — fork пока он больше не сможет этого делать. Когда появляется fork ошибка (то есть: когда моя программа завершилась успешно!), конечный пользователь может отправить CTRL-Zсигнал MAIN_P, который уничтожит P_ROOT и его дочерние элементы.

Я уточняю, что P_ROOT и его дочерние элементы имеют один и тот же GPID (наследование). Но последнее, конечно, отличается от MAIN_P ( setsid применяется к P_ROOT).


Моя проблема

Когда я запускаю свою программу, это fork первый дочерний элемент, который fork является его дочерним элементом до тех пор, пока ОС не будет склеена (т. е. : пока таблица процессов не будет полностью заполнена). Единственная проблема в том, что я не могу CTRL Zв своей консоли остановить это… И, конечно, если я просто выхожу из терминала, это не убивает все эти процессы (и, кроме того, другие продолжают разветвляться).

Таким образом, я не рекомендую вам его выполнять…

Что не так с моим кодом?


Источник

 #include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/resource.h>

int main(int argc, char* argv[]) {
    pid_t pid_first_child = 0;
    if((pid_first_child = fork()) == -1) { // We `fork` the first child, which will always `fork` (more precisely : until the OS is glued, processes table completely filled)
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if(pid_first_child == 0) { // BEGINNING OF <FirstChild>'S CODE

        pid_t pid_session_leader = 0;
        if((pid_session_leader = setsid()) == -1) { // FirstChild is its process group's leader
            perror("setsid");
            exit(EXIT_FAILURE);
        }

        if(setpriority(PRIO_PGRP, pid_session_leader, -10) == -1) { // The priority of FirstChild (which is the group's leader)
            perror("setpriority");
            exit(EXIT_FAILURE);
        }

        unsigned children_counter = 0;
        pid_t pid_calculation_process = 0;
        while((pid_calculation_process = fork()) != -1) { // Now, FirstChild will `fork` until the limit ! When the limit is reached, -1 is returned : there isn't anymore `fork` and we exit the loop
            if(pid_calculation_process > 0) {
                children_counter  ;
                fprintf(stdout, "%un", children_counter);
            } else { // BEGINNING OF <FirstChild's children>'s CODE (Why ? Consequently to the `while` and the `if` !)
                float j=1;
                while(1) { // Children can't die
                    int i = 0;
                    for(; i < 1000; i  ) {
                        j /= 3;
                    }

                    usleep(1000);
                }
            } // END OF <FirstChild's children>'s CODE (FirstChild's children)
        }
        perror("fork"); // It's what we wanted ! This message will tell the user "OS is glued, program worked correctly"
        exit(EXIT_SUCCESS); // `EXIT_SUCCESS` ? Because we reached the limit !

    } // END OF <FirstChild>'S CODE
}
  

Комментарии:

1. Попробуйте использовать ulimit -u 50 , чтобы установить ограничение процесса перед запуском программы. Когда вы достигнете предела, вы должны получить сообщение об ошибке.

2. Подсказка: ваш // nota bene не имеет особого смысла. Когда люди привыкли, что «p_» имеет определенное значение, тогда не «переопределяйте это значение. Такие первоначальные комментарии рано или поздно будут пропущены. Значение: никогда не создавайте код, который может удивить его читателей!

3. @Barmar : Я не хочу устанавливать ограничение процесса на самом деле. Я действительно хочу полностью заполнить таблицу процессов и склеить ОС. Тем не менее, я хочу иметь возможность в терминале с помощью CTRL Z убивать все процессы и, таким образом, освобождать таблицу процессов.

4. @GhostCat : спасибо ! Я полностью изменил свой код (и обнаружил новую проблему: я не могу убить процессы с помощью CTRL Z); новый короче. И я тоже изменил имена.

5. Примечание: я хотел написать CTRL C, а не CTRL Z (извините, не могу отредактировать свой комментарий)

Ответ №1:

Комментарии:

  • Чтобы быстро достичь своего предела fork(), вы должны убедиться, что каждый разветвленный процесс не потребляет слишком много ресурсов. Ваши разветвленные процессы вращаются в цикле for и занимают слишком много ресурсов. Если вы удалите цикл for, вы быстрее достигнете предела процесса, поскольку процессы будут заблокированы при вызове sleep() вместо вращения.
  • Вам не нужен цикл ожидания, чтобы дождаться завершения процессов после ошибки fork() . Это произойдет автоматически.

Обновленный исходный код:

 #include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>

int main(int argc, char* argv[]) {
    // This (first !) child, say "P_ROOT", will create its own children, which will glue the system (thus, MAIN_P is freed
    int p_root = fork();
    if(p_root == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    // P_ROOT's PGID will be set to its PID (so we have : P_ROOT's PGID != MAIN_P's PGID)
    if (p_root == 0) {
       if(setpgid(p_root, p_root) == -1) {
          perror("setpgid");
          exit(EXIT_FAILURE);
       }

       int p_root_number_of_created_children = 0;
       pid_t p_root_child = 0;
       while((p_root_child = fork()) != -1) { // P_ROOT forks until it can't do it anymore...
          if(p_root_child != 0) {
             p_root_number_of_created_children  ;
          } else {
#ifdef CONSUME_RESOURCES
             int i = 0;
             while(i < 1000000000000000000) {
                i  ;
             }
#endif
             sleep(6000);
             exit(EXIT_FAILURE);
          }
       }

       // NOW it's impossible to create new child processes
       perror("fork");
       fprintf(stdout, "nImpossible to create more children. Their number is : %dn", p_root_number_of_created_children);
       exit(EXIT_SUCCESS);
    } else {
       printf("Waiting, top level, root = %dn", p_root);
       wait(NULL); // MAIN_P waits for P_ROOT

       char cmd = 0;

       if(scanf("%c", amp;cmd) < 0) {
          perror("scanf");
          exit(EXIT_FAILURE);
       }

       if(cmd == 'n' amp;amp; kill(-p_root, SIGKILL) == -1) {
          perror("kill");
          exit(EXIT_FAILURE);
       }

       exit(EXIT_SUCCESS);
    }
}
  

Комментарии:

1. С вашим (и моим) кодом я не мог убить свои процессы с n помощью или CTRL Z. Я написал другой код, короче. С этим новым я даже не могу выполнить CTRL Z (похоже, терминал игнорирует его), и, конечно, ни один процесс не будет убит. Более того, fork новые процессы продолжаются: у меня нет никакого контроля над моей ОС, которую я должен перезапускать каждый раз, когда я выполняю свою программу … (к счастью, я использую VB). Не могли бы вы взглянуть на мой новый более короткий код, пожалуйста? Я прокомментировал это подробно.

2. Примечание: я хотел написать CTRL C, а не CTRL Z (извините, не могу отредактировать свой комментарий)