1

我编写了以下 C 程序来限制该程序可以创建的最大进程(在 Linux 中)。本程序使用setrlimit(),预计本程序最多可创建 4 个进程。

// nproc.c
#include <stdio.h>
#include <unistd.h>
#include <sys/resource.h>

int main()
{
    struct rlimit rlim;
    rlim.rlim_cur = rlim.rlim_max = 4;
    setrlimit(RLIMIT_NPROC, &rlim);
    for (int i = 0; i < 3; ++i) printf("%d\n", fork());
    sleep(1);
    return 0;
}

当我以普通用户身份编译并运行该程序时,它会给出以下输出:

$ ./nproc
-1
-1
-1

-1表示fork()失败并且 rlimit 正常工作以限制程序可以创建的最大进程。但是当我以 root 身份运行这个程序时,它会给出以下输出:

$ sudo ./nproc
25926
25927
25928
0
0
25929
0
25930
25931
0
0
0
25932
0

我们可以看到所有的fork()成功并且 rlimit 不能正常工作。问题出在哪里?

4

1 回答 1

0

以下建议的代码:

  1. 干净地编译
  2. 无法执行所需的功能(?为什么?)
  3. 包含所有需要的头文件
  4. 只有“父”尝试创建子进程
  5. 注意:OP 和提议的程序都退出而不等待子进程完成。IE 主程序应该是调用wait()wait_pid()为每个子进程启动的。
  6. 注意:对sleep(1)保持输出良好和有条理的调用。但是,在此期间sleep子进程完成并退出,因此实际上任何时候只有 1 个子进程在运行,因此即使调用setrlimit()成功,“fork()”循环也可能永远运行。

现在,建议的代码:

#include <stdio.h>
#include <stdlib.h>

#include <sys/time.h>
#include <sys/resource.h>

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

int main( void )
{
    struct rlimit rlim;
    rlim.rlim_cur = rlim.rlim_max = 4;

    if( getrlimit(RLIMIT_NPROC, &rlim) == -1 )
    {
        perror( "getrlimit failed" );
        exit( EXIT_FAILURE );
    }

    if( setrlimit(RLIMIT_NPROC, &rlim) == -1 )
    {
        perror( "setrlimit failed" );
        exit( EXIT_FAILURE );
    }

    for (int i = 0; i < 4; ++i) 
    {
        pid_t pid = fork();
        switch( pid )
        {
            case -1:
            perror( "fork failed" );
            exit( EXIT_FAILURE );
            break;

            case 0:
            printf( "child pid: %d\n", getpid() );
            exit( EXIT_SUCCESS );
            break;

            default:
            printf( "parent pid: %d\n", getpid() );
            break;
        }
        sleep(1);
    }
    return 0;
}

运行程序会导致:

fork failed: Resource temporarily unavailable

这表明调用有问题setrlimit()

从手册页:

RLIMIT_NPROC
          This is a limit on the number of extant process (or,  more  pre‐
          cisely  on  Linux,  threads) for the real user ID of the calling
          process.  So long as the current number of  processes  belonging
          to  this process's real user ID is greater than or equal to this
          limit, fork(2) fails with the error EAGAIN.

          The RLIMIT_NPROC limit is not enforced for processes  that  have
          either the CAP_SYS_ADMIN or the CAP_SYS_RESOURCE capability.

所以,调用setrlimit()是限制线程的数量,而不是子进程的数量

但是,如果我们在调用之后立即添加几个打印语句getrlimit()并在调用结果之后再次添加setrlimit()

    if( getrlimit(RLIMIT_NPROC, &rlim) == -1 )
    {
        perror( "getrlimit failed" );
        exit( EXIT_FAILURE );
    }

    printf( "soft limit: %d\n", (int)rlim.rlim_cur );
    printf( "hard limit: %d\n\n", (int)rlim.rlim_max );

    if( setrlimit(RLIMIT_NPROC, &rlim) == -1 )
    {
        perror( "setrlimit failed" );
        exit( EXIT_FAILURE );
    }


    if( getrlimit(RLIMIT_NPROC, &rlim) == -1 )
    {
        perror( "getrlimit failed" );
        exit( EXIT_FAILURE );
    }

    printf( "soft limit: %d\n", (int)rlim.rlim_cur );
    printf( "hard limit: %d\n\n", (int)rlim.rlim_max );

那么结果是:

soft limit: 27393
hard limit: 27393

soft limit: 27393
hard limit: 27393

parent pid: 5516
child pid: 5517
parent pid: 5516
child pid: 5518
parent pid: 5516
child pid: 5519
parent pid: 5516
child pid: 5520

这表明调用:setrlimit()实际上并没有改变子进程的限制

注意:我正在运行 ubuntu linux 18.04

于 2019-02-24T20:43:10.040 回答