【问题标题】:NPTL caps maximum threads at 65528?NPTL 将最大线程数限制为 65528?
【发布时间】:2011-04-01 02:13:01
【问题描述】:

下面的代码应该可以创建 100,000 个线程:

/* compile with:   gcc -lpthread -o thread-limit thread-limit.c */
/* originally from: http://www.volano.com/linuxnotes.html */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>

#define MAX_THREADS 100000
int i;

void run(void) {
  sleep(60 * 60);
}

int main(int argc, char *argv[]) {
  int rc = 0;
  pthread_t thread[MAX_THREADS];
  printf("Creating threads ...\n");
  for (i = 0; i < MAX_THREADS && rc == 0; i++) {
    rc = pthread_create(&(thread[i]), NULL, (void *) &run, NULL);
    if (rc == 0) {
      pthread_detach(thread[i]);
      if ((i + 1) % 100 == 0)
    printf("%i threads so far ...\n", i + 1);
    }
    else
    {
      printf("Failed with return code %i creating thread %i (%s).\n",
         rc, i + 1, strerror(rc));

      // can we allocate memory?
      char *block = NULL;
      block = malloc(65545);
      if(block == NULL)
        printf("Malloc failed too :( \n");
      else
        printf("Malloc worked, hmmm\n");
    }
  }
sleep(60*60); // ctrl+c to exit; makes it easier to see mem use
  exit(0);
}

这是在具有 32GB RAM 的 64 位机器上运行的;已安装 Debian 5.0,所有库存。

  • ulimit -s 512 减小堆栈大小
  • /proc/sys/kernel/pid_max 设置为 1,000,000(默认情况下,它的上限为 32k pid)。
  • ulimit -u 1000000 增加最大进程数(不认为这很重要)
  • /proc/sys/kernel/threads-max 设置为 1,000,000(默认情况下根本没有设置)

运行它会输出以下内容:

65500 threads so far ...
Failed with return code 12 creating thread 65529 (Cannot allocate memory).
Malloc worked, hmmm

我当然没有用完 ram;我什至可以同时启动多个这样的程序,它们都启动它们的 65k 线程。

(请不要建议我不要尝试启动 100,000+ 个线程。这是对应该工作的一些东西的简单测试。我当前基于 epoll 的服务器始终有大约 200k+ 个连接和@987654321 @ 会建议线程可能是一个更好的选择。-谢谢:))

【问题讨论】:

  • ulimit -s 512 实际上将最小堆栈大小设置为 512 KB,而不是 512 字节。因此,100,000 个线程将接近 50GB(但是,这可能不是问题,因为堆栈是按需分配的)。
  • 是的,我尝试将其设置为简单的 ulimit -s 1 并且 65528 个线程的结果是相同的。如果我为此使用 ulimit -s 1024 也是一样。
  • 您能否用 strace(和耐心)确认最终的 pthread_create (clone(2)?) 调用实际上因 ENOMEM 而失败?如果增加/proc/sys/ 文件:vm/max_map_countkernel/pid_maxkernel/threads-max,它们的值是什么,会发生什么?
  • 您的“各种论文”链接指向一篇论文,基本上说如果您将线程库更改为自定义绿色线程实现并且可能也更改编译器,那么线程会很棒。您的测试代码正在使用库存编译器和操作系统线程,所以我不明白为什么您甚至使用那篇论文来支持您尝试这个的决定。此外,该论文忽略了线程从根本上是不确定的这一事实。您应该阅读伯克利其他人的这篇较新的论文:eecs.berkeley.edu/Pubs/TechRpts/2006/EECS-2006-1.pdf
  • 请将您的解决方案放在答案中,以便我们投票:)。

标签: c linux multithreading pthreads nptl


【解决方案1】:

pilcrow 提到/proc/sys/vm/max_map_count 是正确的;提高此值允许打开更多线程;不确定所涉及的确切公式,但 1mil+ 值允许大约 300k+ 线程。

(对于其他尝试使用 100k+ 线程的人,请查看pthread_create's mmap 问题...当较低的内存用完时,使新线程变得非常慢非常快。)

【讨论】:

    【解决方案2】:

    一个可能的问题是主程序中的局部变量thread。我认为 pthread_t 在您的 64 位机器上将是 8 个字节(假设是 64 位版本)。那将是堆栈上的 800,000 个字节。我认为您的 512K 堆栈限制将是一个问题。 512K / 8 = 65536,这可疑地接近您正在创建的线程数。您可以尝试动态分配该数组,而不是将其放入堆栈。

    【讨论】:

    • 也可以单独为初始线程保留堆栈大小,只为以后的线程更改(即使用pthread_attr_setstack() 为您创建的每个线程设置堆栈大小)
    【解决方案3】:

    这可能有助于将程序中的堆栈大小设置为可以达到的最小(如果这还不够你选择):

    /* compile with:   gcc -lpthread -o thread-limit thread-limit.c */
    /* originally from: http://www.volano.com/linuxnotes.html */
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <string.h>
    
    #define MAX_THREADS 100000
    int i;
    
    void run(void) {
      sleep(60 * 60);
    }
    
    int main(int argc, char *argv[]) {
      int rc = 0;
      pthread_t thread[MAX_THREADS];
      pthread_attr_t thread_attr;
    
      pthread_attr_init(&thread_attr);
      pthread_attr_setstacksize(&thread_attr, PTHREAD_STACK_MIN);
    
      printf("Creating threads ...\n");
      for (i = 0; i < MAX_THREADS && rc == 0; i++) {
        rc = pthread_create(&(thread[i]), &thread_attr, (void *) &run, NULL);
        if (rc == 0) {
          pthread_detach(thread[i]);
          if ((i + 1) % 100 == 0)
        printf("%i threads so far ...\n", i + 1);
        }
        else
        {
          printf("Failed with return code %i creating thread %i (%s).\n",
             rc, i + 1, strerror(rc));
    
          // can we allocate memory?
          char *block = NULL;
          block = malloc(65545);
          if(block == NULL)
            printf("Malloc failed too :( \n");
          else
            printf("Malloc worked, hmmm\n");
        }
      }
    sleep(60*60); // ctrl+c to exit; makes it easier to see mem use
      exit(0);
    }
    

    此外,您可以在调用pthread_attr_setstacksize() 之后添加这样的调用:pthread_attr_setguardsize(&amp;thread_attr, 0);,但随后您将完全失去堆栈溢出检测,它只会为您节省 4k 的地址空间和零实际内存。

    【讨论】:

      【解决方案4】:

      您是否正在尝试搜索一个公式来计算每个进程可能的最大线程数?

      Linux 间接实现了每个进程的最大线程数!!

      number of threads = total virtual memory / (stack size*1024*1024)
      

      因此,可以通过增加总虚拟内存或减少堆栈大小来增加每个进程的线程数。但是,在最大虚拟内存等于交换内存的情况下,过多减小堆栈大小会导致堆栈溢出导致代码失败。

      检查你的机器:

      总虚拟内存:ulimit -v(默认为无限制,因此您需要增加交换内存来增加)

      总堆栈大小:ulimit -s(默认为 8Mb)

      增加这些值的命令:

      ulimit -s newvalue
      
      ulimit -v newvalue
      

      *将新值替换为您要设置为限制的值。

      参考资料:

      http://dustycodes.wordpress.com/2012/02/09/increasing-number-of-threads-per-process/

      【讨论】:

        猜你喜欢
        • 2018-08-04
        • 1970-01-01
        • 2011-02-09
        • 2020-04-09
        • 2019-03-19
        • 1970-01-01
        • 2023-03-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多