prlimit64系统调用及示例

prlimit64 函数

1. 函数介绍

prlimit64 用于获取和设置进程的资源限制。它是 getrlimit 和 setrlimit 的增强版本,支持64位资源限制值。

2. 函数原型

#define _GNU_SOURCE
#include <sys/resource.h>
int prlimit64(pid_t pid, int resource, const struct rlimit64 *new_limit, struct rlimit64 *old_limit);

3. 功能

获取和/或设置指定进程的资源限制。可以用于控制进程使用的各种系统资源,如内存、文件描述符、CPU时间等。

4. 参数

  • pid_t pid: 目标进程ID(0表示当前进程)
  • int resource: 资源类型(如RLIMIT_AS, RLIMIT_NOFILE等)
  • *const struct rlimit64 new_limit: 新的资源限制(NULL表示不设置)
  • *struct rlimit64 old_limit: 保存旧的资源限制(NULL表示不获取)

5. 返回值

  • 成功: 返回0
  • 失败: 返回-1,并设置errno

6. 相似函数,或关联函数

  • getrlimit/setrlimit: 32位版本
  • ulimit: shell内置命令
  • getrusage: 获取资源使用情况

7. 示例代码

#define _GNU_SOURCE
#include <sys/resource.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

/**
 * 显示资源限制信息
 */
void display_resource_limit(int resource, const char *name) {
    struct rlimit64 limit;
    
    if (prlimit64(0, resource, NULL, &limit) == 0) {
        printf("%-20s: ", name);
        if (limit.rlim_cur == RLIM64_INFINITY) {
            printf("无限制");
        } else {
            printf("软限制=%lld", (long long)limit.rlim_cur);
        }
        
        if (limit.rlim_max == RLIM64_INFINITY) {
            printf(", 硬限制=无限制\n");
        } else {
            printf(", 硬限制=%lld\n", (long long)limit.rlim_max);
        }
    } else {
        printf("%-20s: 获取失败 (%s)\n", name, strerror(errno));
    }
}

/**
 * 演示prlimit64获取资源限制
 */
int demo_prlimit64_get() {
    printf("=== prlimit64 获取资源限制示例 ===\n");
    
    // 显示常见的资源限制
    display_resource_limit(RLIMIT_AS, "虚拟内存");
    display_resource_limit(RLIMIT_CORE, "核心文件大小");
    display_resource_limit(RLIMIT_CPU, "CPU时间");
    display_resource_limit(RLIMIT_DATA, "数据段大小");
    display_resource_limit(RLIMIT_FSIZE, "文件大小");
    display_resource_limit(RLIMIT_NOFILE, "文件描述符数");
    display_resource_limit(RLIMIT_NPROC, "进程数");
    display_resource_limit(RLIMIT_STACK, "栈大小");
    
    return 0;
}

/**
 * 演示prlimit64设置资源限制
 */
int demo_prlimit64_set() {
    struct rlimit64 old_limit, new_limit;
    int result;
    
    printf("\n=== prlimit64 设置资源限制示例 ===\n");
    
    // 获取当前文件描述符限制
    if (prlimit64(0, RLIMIT_NOFILE, NULL, &old_limit) == 0) {
        printf("当前文件描述符限制: 软限制=%lld, 硬限制=%lld\n",
               (long long)old_limit.rlim_cur, (long long)old_limit.rlim_max);
    }
    
    // 尝试设置新的文件描述符限制
    new_limit.rlim_cur = 1024;  // 软限制
    new_limit.rlim_max = 2048;  // 硬限制
    
    result = prlimit64(0, RLIMIT_NOFILE, &new_limit, NULL);
    if (result == 0) {
        printf("成功设置新的文件描述符限制\n");
        
        // 验证设置结果
        if (prlimit64(0, RLIMIT_NOFILE, NULL, &old_limit) == 0) {
            printf("设置后文件描述符限制: 软限制=%lld, 硬限制=%lld\n",
                   (long long)old_limit.rlim_cur, (long long)old_limit.rlim_max);
        }
    } else {
        printf("设置文件描述符限制失败: %s\n", strerror(errno));
        printf("注意:可能需要root权限或在硬限制范围内调整\n");
    }
    
    // 演示内存限制设置
    printf("\n尝试设置虚拟内存限制:\n");
    new_limit.rlim_cur = 100 * 1024 * 1024;  // 100MB
    new_limit.rlim_max = 200 * 1024 * 1024;  // 200MB
    
    result = prlimit64(0, RLIMIT_AS, &new_limit, NULL);
    if (result == 0) {
        printf("成功设置虚拟内存限制为100MB\n");
    } else {
        printf("设置虚拟内存限制失败: %s\n", strerror(errno));
    }
    
    return 0;
}

/**
 * 演示资源限制的实际影响
 */
int demo_resource_limit_effect() {
    struct rlimit64 limit;
    int fd_array[100];
    int i, fd_count = 0;
    
    printf("\n=== 资源限制实际影响演示 ===\n");
    
    // 获取当前文件描述符限制
    if (prlimit64(0, RLIMIT_NOFILE, NULL, &limit) == 0) {
        printf("当前文件描述符软限制: %lld\n", (long long)limit.rlim_cur);
    }
    
    // 尝试打开大量文件来测试限制
    printf("尝试打开文件...\n");
    for (i = 0; i < 100; i++) {
        char filename[32];
        snprintf(filename, sizeof(filename), "test_file_%d.txt", i);
        
        int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
        if (fd == -1) {
            printf("在打开第 %d 个文件时失败: %s\n", i, strerror(errno));
            printf("当前已打开 %d 个文件\n", fd_count);
            break;
        }
        
        fd_array[fd_count++] = fd;
        
        if (i % 20 == 0) {
            printf("已成功打开 %d 个文件\n", fd_count);
        }
    }
    
    // 关闭所有打开的文件
    for (i = 0; i < fd_count; i++) {
        close(fd_array[i]);
        char filename[32];
        snprintf(filename, sizeof(filename), "test_file_%d.txt", i);
        unlink(filename);
    }
    
    printf("清理完成\n");
    return 0;
}

int main() {
    if (demo_prlimit64_get() == 0) {
        demo_prlimit64_set();
        demo_resource_limit_effect();
        printf("\n=== prlimit64 使用总结 ===\n");
        printf("用途:控制进程资源使用,防止资源耗尽\n");
        printf("注意:某些限制需要特权权限才能修改\n");
        printf("常见资源类型:内存、文件描述符、CPU时间、进程数等\n");
    }
    return 0;
}

总结

这些系统调用提供了强大的文件I/O和资源管理功能:

文件I/O函数特点:

1. pread/pwrite: 原子性的定位读写,线程安全
2. preadv/pwritev: 分散/聚集I/O,一次系统调用处理多个缓冲区
3. preadv2/pwritev2: 增强版本,支持额外控制标志

资源管理函数:

1. prlimit64: 现代化的资源限制管理,支持64位值

使用建议:

1. 选择合适的函数: 根据具体需求选择单缓冲区或多缓冲区版本
2. 注意权限要求: 某些操作需要相应权限
3. 错误处理: 始终检查返回值并处理错误
4. 性能考虑: 合理使用分散/聚集I/O减少系统调用次数

此条目发表在linux文章分类目录。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注