一尘不染

pthread_create可以创建的最大线程数是多少?

linux

我使用下面的代码来测试pthread_create函数可以创建的最大线程数。

#include <pthread.h>
#include <stdio.h>

static unsigned long long thread_nr = 0;

pthread_mutex_t mutex_;

void* inc_thread_nr(void* arg) {
    (void*)arg;
    pthread_mutex_lock(&mutex_);
    thread_nr ++;
    pthread_mutex_unlock(&mutex_);

    /* printf("thread_nr = %d\n", thread_nr); */

    sleep(300000);
}

int main(int argc, char *argv[])
{
    int err;
    int cnt = 0;

    pthread_t pid[1000000];

    pthread_mutex_init(&mutex_, NULL);

    while (cnt < 1000000) {

        err = pthread_create(&pid[cnt], NULL, (void*)inc_thread_nr, NULL);
        if (err != 0) {
            break;
        }
        cnt++;
    }

    pthread_join(pid[cnt], NULL);

    pthread_mutex_destroy(&mutex_);
    printf("Maximum number of threads per process is = %d\n", thread_nr);
}

输出为:

Maximum number of threads per process is = 825

那是pthread_create函数可以创建的最大线程数吗?

此外,我使用以下命令查看系统允许的最大线程数:

# cat /proc/sys/kernel/threads-max

号码是772432。

为什么我的程序输出不等于值threads-max

我的操作系统是Fodaro 16,具有12核,48G RAM。


阅读 598

收藏
2020-06-03

共1个答案

一尘不染

每个线程堆栈的默认大小是在测试中人为施加的限制。当分配给进程的默认堆栈(初始线程)根据需要动态增长时,其他线程的堆栈大小是固定的。默认大小通常非常大,大约为2兆字节,以确保每个线程堆栈都足够大,甚至可以用于病理情况(深度递归等)。

在大多数情况下,线程工作者只需要很少的堆栈。我发现,在我使用的所有体系结构上,只要不使用深度递归算法或大型局部变量(结构或数组),每个线程堆栈64k(65536字节)就足够了。

要显式指定每个线程的堆栈大小,请将您main()的内容修改为如下所示:

#define MAXTHREADS 1000000
#define THREADSTACK  65536

int main(int argc, char *argv[])
{
    pthread_t       pid[MAXTHREADS];
    pthread_attr_t  attrs;
    int  err, i;
    int  cnt = 0;

    pthread_attr_init(&attrs);
    pthread_attr_setstacksize(&attrs, THREADSTACK);

    pthread_mutex_init(&mutex_, NULL);

    for (cnt = 0; cnt < MAXTHREADS; cnt++) {

        err = pthread_create(&pid[cnt], &attrs, (void*)inc_thread_nr, NULL);
        if (err != 0)
            break;
    }

    pthread_attr_destroy(&attrs);

    for (i = 0; i < cnt; i++)
        pthread_join(pid[i], NULL);

    pthread_mutex_destroy(&mutex_);

    printf("Maximum number of threads per process is %d (%d)\n", cnt, thread_nr);
}

请注意,attrspthread_create()调用不会消耗它。将线程属性想像成如何pthread_create()创建线程的模板;
它们不是赋予线程的属性 。这绊倒了许多有抱负的pthread程序员,所以这是您最好从一开始就做好的事情之一。

至于堆栈大小本身,它必须至少是PTHREAD_STACK_MIN(我相信在Linux中为16384)并可以被整除sysconf(_SC_PAGESIZE)。由于页面大小在所有体系结构上都是2的幂,因此始终应该使用足够大的2的幂。

另外,我也在那里添加了修复程序。您仅尝试加入一个不存在的线程(该循环尝试创建但失败的线程),但是您需要加入所有线程(以确保它们都已完成工作)。

进一步建议的修复程序:

代替使用睡眠,请使用条件变量。让每个线程pthread_cond_wait()在条件变量上等待()(同时保持互斥锁),然后释放互斥锁并退出。这样,您的主要函数只需要pthread_cond_broadcast()在条件变量上广播()即可告诉所有线程现在可以退出,然后可以将其加入每个线程,并且可以确保确实有多个线程在同时运行。就目前的代码而言,某些线程可能有足够的时间从睡眠中唤醒并退出。

2020-06-03