Максимальный поток на процесс в 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;
}
Другие вопросы по тегам