setrlimit()不影响派生的std::线程

setrlimit() not affecting spawned std::threads

本文关键字:std 派生 线程 影响 setrlimit      更新时间:2023-10-16

我目前正在开发一个同时加载和转换多个图像的管道。由于这种情况同时发生在许多图像上(1440),因此内存占用相当大。因此,我试图实现一个基于setrlimit的内存管理系统,但它似乎不会影响派生的线程(std::thread),因为它们会很高兴地忽略限制——我知道这一点是因为在线程函数中调用了getrlimit()——并最终导致我的程序被终止。这是我用来设置限制的代码:

void setMemoryLimit(std::uint64_t bytes)
{
    struct rlimit limit;
    getrlimit(RLIMIT_AS, &limit);
    if(bytes <= limit.rlim_max)
    {
        limit.rlim_cur = bytes;
        std::cout << "New memory limit: " << limit.rlim_cur << " bytes" << std::endl;
    }
    else
    {
        limit.rlim_cur = limit.rlim_max;
        std::cout << "WARNING: Memory limit couldn't be set to " << bytes << " bytes" << std::endl;
        std::cout << "New memory limit: " << limit.rlim_cur << " bytes" << std::endl;
    }
    if(setrlimit(RLIMIT_AS, &limit) != 0)
        std::perror("WARNING: memory limit couldn't be set:");
    // included for debugging purposes
    struct rlimit tmp;
    getrlimit(RLIMIT_AS, &tmp);
    std::cout << "Tmp limit: " << tmp.rlim_cur << " bytes" << std::endl; // prints the correct limit
}

我在用Linux。手册页指出setrlimit会影响整个过程,所以我有点不知道为什么线程似乎没有受到影响。

Edit:顺便说一下,上面的函数是在main()的开头调用的。

这个问题很难找到,因为它由两个完全独立的组件组成:

  1. 我的可执行文件是用-fomit框架指针编译的。这将导致限值的重置。参见以下示例:

    /* rlimit.cpp */
    #include <iostream>
    #include <thread>
    #include <vector>
    #include <sys/resource.h>
    class A
    {
        public:
            void foo()
            {
                struct rlimit limit;
                getrlimit(RLIMIT_AS, &limit);
                std::cout << "Limit: " << limit.rlim_cur << std::endl;
            }
    };
    int main()
    {
        struct rlimit limit;
        limit.rlim_cur = 500 * 1024 * 1024;
        setrlimit(RLIMIT_AS, &limit);
        std::cout << "Limit: " << limit.rlim_cur << std::endl;
        std::vector<std::thread> t;
        for(int i = 0; i < 5; i++)
        {
            A a;
            t.push_back(std::thread(&A::foo, &a));
        }
        for(auto thread : t)
            thread.join();
        return 0;
    }
    

    输出:

    > g++ -std=c++11 -pthread -fomit-frame-pointer rlimit.cpp -o limit
    > ./limit
    Limit: 524288000
    Limit: 18446744073709551615
    Limit: 18446744073709551615
    Limit: 18446744073709551615
    Limit: 18446744073709551615
    Limit: 18446744073709551615
    > g++ -std=c++11 -pthread rlimit.cpp -o limit
    > ./limit
    Limit: 524288000
    Limit: 524288000
    Limit: 524288000
    Limit: 524288000
    Limit: 524288000
    Limit: 524288000
    
  2. 对于图像处理部分,我使用OpenCL。显然,NVIDIA的实现调用了setrlimit,并将限制推到了rlim_max。