我编写了以下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不能正常工作。问题出在哪里?
答案 0 :(得分:0)
以下建议的代码:
wait()
或wait_pid()
。sleep(1)
的调用使输出保持美观和井井有条。但是,在该sleep
子进程完成并退出的过程中,实际上在任何时候都只有一个子进程在运行,因此即使对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()
在MAN页面:
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