【问题标题】:What is the maximum number of threads that pthread_create can create? [duplicate]pthread_create 可以创建的最大线程数是多少? [复制]
【发布时间】:2012-09-12 12:06:19
【问题描述】:

可能重复:
The thread create by pthread_create the same with the kernel thread?

我使用下面的代码来测试 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。

【问题讨论】:

  • pthread_create() 函数只能创建一个线程。您可以多次调用它——显然 825 没有错误。这可能会随着系统加载、流程变化和其他变量的变化而变化。
  • @iccthedral 它们不是重复的。他们关注不同的方面和不同的问题。
  • 请告诉我为什么需要这么多线程?
  • 请告诉我们errno您观察到了什么。
  • 最后一行应该是printf("Maximum number of threads per process is = %d\n", cnt);

标签: c linux pthreads


【解决方案1】:

每个线程堆栈的默认大小是在您的测试中人为地施加限制。虽然赋予进程(初始线程)的默认堆栈根据需要动态增长,但其他线程的堆栈大小是固定的。默认大小通常非常大,大约 2 MB,以确保每个线程的堆栈足够大,即使是病态的情况(深度递归等)。

在大多数情况下,线程工作者只需要很少的堆栈。我发现在我使用的所有架构中,每个线程 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);
}

请注意,attrs 不会被 pthread_create() 调用使用。将线程属性想象成pthread_create() 应该如何创建线程的模板; 它们不是赋予线程的属性。这让许多有抱负的 pthreads 程序员感到困惑,所以这是你最好从一开始就做好的事情之一。

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

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

进一步推荐的修复:

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

【讨论】:

  • 请注意,&lt;limits.h&gt; 应该定义 PTHREAD_STACK_MIN,这是架构所需的线程函数的最小堆栈大小。所以,你可以使用例如#define THREADSTACK (PTHREAD_STACK_MIN + 32768),虽然为了便携性,您应该将其四舍五入为 sysconf(_SC_PAGESIZE) 的倍数。
【解决方案2】:

理论上,一个进程可以拥有的线程数没有限制。但实际的限制可能来自所有线程共享资源这一事实。

这意味着在某些时候,例如,由于缺乏与此类堆栈空间共享的资源,一个进程无法创建超过一定数量的进程。

【讨论】:

  • 很可能由于堆栈过多而导致内存不足。在 32 位机器上,默认堆栈大小为 2M,因此 825 个线程超过 1.5 gigs 的内存。 64 位系统使用 8M 堆栈,因此超过 6.5 gig。
  • @Joachim:所以32位版本可能已经耗尽了附近的地址空间,无法分配更多。 64 位版本可能会继续运输,6.5GB 的地址空间很小,所以这个观察到的限制可能不仅仅是堆栈的总和。
  • 理论上,有一个限制:2^(CHAR_BIT*sizeof(pthread_t)...
  • @SteveJessop:线程堆栈也消耗提交费用,而不仅仅是虚拟地址空间。 6.5 GB 听起来可能是(swap + ram/2) 的可能值,这是 Linux 上的默认提交费用限制。默认情况下,Linux 不会执行严格的提交记帐,但它会尝试防止严重的过度提交。
  • @R..:嗯,提问者声称有 48GB 内存。
【解决方案3】:

根据pthread_create(3) man page,还有一个限制:

RLIMIT_NPROC soft resource limit (set via setrlimit(2)), which limits the number 
of process  for  a real user ID.

尝试使用getrlimit(2) 查找此限制的值。如果该值仍然与您测量的数字 (825) 不匹配,请尝试使用 setrlimit(2) 更改此限制,以验证它是否会影响您的测量。

编辑:事实上,RLIMIT_NPROC 限制值与使用 shell 命令 ulimit -u(打印/设置最大用户进程)获得的限制值相同。

【讨论】:

    猜你喜欢
    • 2012-01-04
    • 2016-09-21
    • 2018-09-09
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多