#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 (извините, не могу отредактировать свой комментарий)