NPTL ограничивает максимальные потоки в 65528?

Следующий код должен создать 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);
}

Это работает на 64-битной машине с 32 ГБ оперативной памяти; Debian 5.0 установлен, все сток.

  • ulimit -s 512, чтобы уменьшить размер стека
  • Для /proc/sys/kernel/pid_max установлено значение 1,000,000 (по умолчанию он ограничен 32 тыс. пид).
  • 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

Я, конечно, не хватает баранов; Я даже могу запустить еще несколько этих программ, работающих одновременно, и все они запускают свои потоки по 65 тыс.

(Пожалуйста, воздержитесь от предложения, чтобы я не пытался запускать более 100 000 потоков. Это простое тестирование того, что должно работать. Мой текущий сервер на основе epoll всегда имеет около 200 000 подключений +, и в различных статьях можно предположить, что потоки могут быть лучшим вариантом.. - Спасибо:))

4 ответа

Решение

Упоминание Пикроу о /proc/sys/vm/max_map_count находится на правильном пути; повышение этого значения позволяет открывать больше потоков; не уверен в точной формуле, но значение 1mil+ учитывает около 300k+ потоков.

(Для всех, кто экспериментирует с потоками 100k +, посмотрите на проблемы mmap в pthread_create... создание новых потоков становится очень медленным и очень быстрым, когда используется меньше памяти.)

Это может помочь установить размер стека в программе на наименьшее значение (если этого недостаточно, вы выбираете):

/* 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_setguardsize(&thread_attr, 0); сразу после звонка pthread_attr_setstacksize() но тогда вы полностью потеряете обнаружение переполнения стека, и это сэкономит вам только 4 Кб адресного пространства и ноль фактической памяти.

Одной из возможных проблем является локальная переменная thread в основной программе. Я думаю, что pthread_t будет 8 байтов на вашей 64-битной машине (при условии 64-битной сборки). Это было бы 800 000 байтов в стеке. Ваш предел стека в 512К был бы проблемой, я думаю. 512K / 8 = 65536, что подозрительно близко к числу создаваемых вами потоков. Вы можете попытаться динамически выделить этот массив вместо помещения его в стек.

Вы пытаетесь найти формулу для расчета максимально возможных потоков на процесс?

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/

Другие вопросы по тегам