【问题标题】:How to glue the system thanks to processes?如何通过流程粘合系统?
【发布时间】:2016-10-07 17:59:16
【问题描述】:

关于我的程序功能的一般性和解释

我编写了一个程序,其目的是创建进程,直到它不能再这样做(id est:它必须粘合操作系统并完全填充进程表)。但是,当 OS 被粘上时,会出现类似“fork 无法再完成”的消息,并且所有进程都可以被最终用户杀死,这要归功于 CTRL+Z.

我的程序包含两个重要的过程:主要的一个,它创建第二个。第一个在我的代码中称为“MAIN_P”,后者称为“P_ROOT”。 P_ROOT 的目标是fork,直到他做不到为止。当出现fork 错误时(id est:当我的程序成功时!),最终用户可以向 MAIN_P 发送 CTRL-Z 信号,这将杀死 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, "%u\n", 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
}

【问题讨论】:

  • 在运行程序之前尝试使用ulimit -u 50 设置您的进程限制。当你达到限制时,你应该得到错误。
  • 提示:你的 //nota bene 没有多大意义。当人们使用“p_”具有特定含义时,dont“覆盖该含义。这样的初始 cmets 迟早会被忽略。含义:从不放置代码这可能会让读者惊喜
  • @Barmar :实际上我不想设置进程限制。我真的很想完全填满进程表并粘合操作系统。但是,我希望能够在终端中按 CTRL + Z 杀死所有进程,从而释放进程表。
  • @GhostCat:谢谢!我完全改变了我的代码(并发现了一个新问题:我不能用 CTRL + Z 杀死进程);新的更短。我也改了名字。
  • 注意:我想写 CTRL + C,而不是 CTRL + Z(抱歉,无法编辑我的评论)

标签: c linux process fork


【解决方案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 : %d\n", p_root_number_of_created_children);
       exit(EXIT_SUCCESS);
    } else {
       printf("Waiting, top level, root = %d\n", p_root);
       wait(NULL); // MAIN_P waits for P_ROOT

       char cmd = 0;

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

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

       exit(EXIT_SUCCESS);
    }
}

【讨论】:

  • 使用您(和我)的代码,我无法使用 \n 或 CTRL + Z 终止我的进程。我编写了另一个更短的代码。有了这个新的,我什至不能做 CTRL + Z (它似乎被终端忽略了),当然没有进程被杀死。此外,fork 的新进程还在继续:我对我的操作系统没有任何控制权,每次执行程序时我都必须重新启动它......(幸运的是,我使用的是 VB)。你能看看我新的更短的代码吗?我详细评论了。
  • 注意:我想写 CTRL + C,而不是 CTRL + Z(抱歉无法编辑我的评论)
猜你喜欢
  • 2011-07-11
  • 2011-05-08
  • 2015-07-16
  • 1970-01-01
  • 1970-01-01
  • 2020-08-25
  • 2016-11-23
  • 1970-01-01
  • 2013-11-05
相关资源
最近更新 更多