多线程调用system()报错Resource temporarily unavailable,如何定位资源类型?
定位system()调用资源不足的具体类型
1. 打印具体错误码(errno)
perror仅输出错误描述,无法直接定位资源类型,修改代码打印errno的具体数值和对应说明:
#include <string.h> #include <stdio.h> // ... 其他代码 void* thread_func(void* arg) { if (system("test.sh") == -1) { fprintf(stderr, "system调用失败,errno: %d (%s)\n", errno, strerror(errno)); perror("system"); exit(1); } pthread_exit(NULL); }
不同errno对应不同资源问题:
EAGAIN:通常是fork()失败,可能是进程数、内存、文件描述符等资源不足;ENOMEM:内存不足,无法为子进程分配页表或内存空间。
2. 检查资源限制配置
进程级限制
查看当前进程的资源限制(替换<PID>为主进程ID):
cat /proc/<PID>/limits
重点关注以下项:
Max processes:3000个线程同时调用system()会生成3000个子进程,需确保该值大于当前进程数+3000;Max open files:每个子进程至少占用3个文件描述符(stdin/stdout/stderr),3000个子进程会占用近9000个描述符,需确认该值和系统级限制足够;Max virtual memory/Max memory size:大量进程的页表等开销也可能触发内存限制。
系统级限制
查看系统全局资源限制:
# 查看系统最大PID数 cat /proc/sys/kernel/pid_max # 查看系统最大打开文件数 cat /proc/sys/fs/file-max # 查看当前shell生效的用户进程数限制 ulimit -u
3. 实时监控资源使用
运行程序时,用以下命令实时观察资源变化:
- 监控进程数和内存:
top
关注Tasks栏的总进程数,Mem/Swap栏的使用率;
- 监控系统资源统计:
vmstat 1
关注r(等待运行的进程数)、b(不可中断睡眠的进程数)、si/so(交换分区读写),若si/so持续非零,说明内存不足;
- 监控总打开文件数:
watch -n 1 'lsof | wc -l'
对比系统的fs.file-max值,若接近则是文件描述符不足。
4. 排查fork()失败的根源
system()内部依赖fork()创建子进程,fork()失败是报错的直接原因,常见触发场景:
- 用户进程数超限:需确认之前调整的最大进程数配置是否在当前环境生效;
- 文件描述符耗尽:父进程若打开大量文件,加上子进程继承的描述符,可能超过限制;
- 内存不足:fork()需要为子进程分配页表,若系统剩余内存不足以分配,会触发EAGAIN或ENOMEM。
内容的提问来源于stack exchange,提问作者user3108468
相关产品推荐
相关产品推荐

