Максимальный поток на процесс в Linux
Я написал простую программу для расчета максимального количества потоков, которое может иметь процесс в Linux (Centos 5). вот код:
int main()
{
pthread_t thrd[400];
for(int i=0;i<400;i++)
{
int err=pthread_create(&thrd[i],NULL,thread,(void*)i);
if(err!=0)
cout << "thread creation failed: " << i <<" error code: " << err << endl;
}
return 0;
}
void * thread(void* i)
{
sleep(100);//make the thread still alive
return 0;
}
Я понял, что максимальное количество для потоков только 300!? Что если мне нужно больше, чем это? Я должен упомянуть, что pthread_create возвращает 12 в качестве кода ошибки.
Спасибо, прежде чем
5 ответов
Существует ограничение потока для Linux, и его можно изменить во время выполнения, записав желаемое ограничение в /proc/sys/kernel/threads-max
, Значение по умолчанию вычисляется из доступной системной памяти. В дополнение к этому пределу есть еще один предел: /proc/sys/vm/max_map_count
который ограничивает максимальные сегменты mmapped, и по крайней мере последние ядра будут mmap памяти на поток. Должно быть безопасно увеличить этот лимит, если вы его достигнете.
Предел, которого вы достигаете, - это недостаток виртуальной памяти в 32-битной операционной системе. Установите 64-битный Linux, если ваше оборудование поддерживает его, и все будет в порядке. Я могу легко запустить 30000 потоков с размером стека 8 МБ. Система имеет один Core 2 Duo + 8 ГБ системной памяти (в то же время я использую 5 ГБ для других задач) и работает под управлением 64-битной Ubuntu с ядром 2.6.32. Обратите внимание, что чрезмерное использование памяти (/proc/sys/vm/overcommit_memory) должно быть разрешено, поскольку в противном случае системе потребовалось бы по меньшей мере 240 ГБ памяти для фиксации (сумма реальной памяти и пространства подкачки).
Если вам нужно много потоков и вы не можете использовать 64-битную систему, ваш единственный выбор - минимизировать использование памяти на поток для экономии виртуальной памяти. Начните с запроса как можно меньшего количества стеков.
Ограничения вашей системы могут не позволять вам отображать стеки всех потоков, которые вам нужны. смотреть на /proc/sys/vm/max_map_count
и увидеть этот ответ. Я не уверен на 100%, что это ваша проблема, потому что большинство людей сталкиваются с проблемами при гораздо большем количестве потоков.
Я также столкнулся с той же проблемой, когда мое количество потоков пересекает некоторый порог. Это произошло из-за ограничения уровня пользователя (количество процессов, которое пользователь может запустить за один раз), установленного на 1024 в /etc/security/limits.conf.
так что проверьте ваш /etc/security/limits.conf и найдите запись:-
имя пользователя -/soft/hard -nproc 1024
измените его на несколько больших значений на что-то 100k(требует привилегий sudo /root), и это должно работать для вас.
Чтобы узнать больше о политике безопасности, см. http://linux.die.net/man/5/limits.conf.
Проверьте размер стека на поток с помощью ulimit, в моем случае Redhat Linux 2.6:
ulimit -a
...
stack size (kbytes, -s) 10240
Каждый из ваших потоков получит этот объем памяти (10 МБ) для своего стека. С 32-битной программой и максимальным адресным пространством 4 ГБ, это максимум только 4096 МБ / 10 МБ = 409 потоков!!! Минус программный код, минус куча пространства, вероятно, приведет к вашему наблюдаемому макс. из 300 нитей.
Вы можете поднять это, скомпилировав 64-битное приложение или установив ulimit -s 8192 или даже ulimit -s 4096. Но если это целесообразно, это другое обсуждение...
Вам также не хватит памяти, если вы не уменьшите размер стека по умолчанию. Его 10 МБ на нашей версии Linux.
РЕДАКТИРОВАТЬ: Код ошибки 12 = недостаточно памяти, поэтому я думаю, что стек 1 МБ все еще слишком велик для вас. Скомпилированный для 32-битных, я могу получить стек 100 КБ, чтобы дать мне 30 000 потоков. За 30k потоков я получаю код ошибки 11, что означает, что больше потоков не допускается. Стек 1 МБ дает мне около 4 тыс. Потоков до кода ошибки 12. 10 МБ дает мне 427 потоков. 100 МБ дает мне 42 темы. 1 ГБ дает мне 4... У нас 64-битная ОС с 64 ГБ оперативной памяти. Ваша ОС 32-битная? Когда я компилирую для 64-битной системы, я могу использовать любой размер стека и получить максимальное количество потоков.
Также я заметил, что если я включаю профилирование (Tools|Profiling) для netbeans и запускаю из ide... я могу получить только 400 потоков. Weird. NETbeans также умирает, если вы используете все потоки.
Вот тестовое приложение, которое вы можете запустить:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <signal.h>
// this prevents the compiler from reordering code over this COMPILER_BARRIER
// this doesnt do anything
#define COMPILER_BARRIER() __asm__ __volatile__ ("" ::: "memory")
sigset_t _fSigSet;
volatile int _cActive = 0;
pthread_t thrd[1000000];
void * thread(void *i)
{
int nSig, cActive;
cActive = __sync_fetch_and_add(&_cActive, 1);
COMPILER_BARRIER(); // make sure the active count is incremented before sigwait
// sigwait is a handy way to sleep a thread and wake it on command
sigwait(&_fSigSet, &nSig); //make the thread still alive
COMPILER_BARRIER(); // make sure the active count is decrimented after sigwait
cActive = __sync_fetch_and_add(&_cActive, -1);
//printf("%d(%d) ", i, cActive);
return 0;
}
int main(int argc, char** argv)
{
pthread_attr_t attr;
int cThreadRequest, cThreads, i, err, cActive, cbStack;
cbStack = (argc > 1) ? atoi(argv[1]) : 0x100000;
cThreadRequest = (argc > 2) ? atoi(argv[2]) : 30000;
sigemptyset(&_fSigSet);
sigaddset(&_fSigSet, SIGUSR1);
sigaddset(&_fSigSet, SIGSEGV);
printf("Start\n");
pthread_attr_init(&attr);
if ((err = pthread_attr_setstacksize(&attr, cbStack)) != 0)
printf("pthread_attr_setstacksize failed: err: %d %s\n", err, strerror(err));
for (i = 0; i < cThreadRequest; i++)
{
if ((err = pthread_create(&thrd[i], &attr, thread, (void*)i)) != 0)
{
printf("pthread_create failed on thread %d, error code: %d %s\n",
i, err, strerror(err));
break;
}
}
cThreads = i;
printf("\n");
// wait for threads to all be created, although we might not wait for
// all threads to make it through sigwait
while (1)
{
cActive = _cActive;
if (cActive == cThreads)
break;
printf("Waiting A %d/%d,", cActive, cThreads);
sched_yield();
}
// wake em all up so they exit
for (i = 0; i < cThreads; i++)
pthread_kill(thrd[i], SIGUSR1);
// wait for them all to exit, although we might be able to exit before
// the last thread returns
while (1)
{
cActive = _cActive;
if (!cActive)
break;
printf("Waiting B %d/%d,", cActive, cThreads);
sched_yield();
}
printf("\nDone. Threads requested: %d. Threads created: %d. StackSize=%lfmb\n",
cThreadRequest, cThreads, (double)cbStack/0x100000);
return 0;
}