11

可能重复:
pthread_create 创建的线程与内核线程相同吗?

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

4

3 回答 3

11

每个线程堆栈的默认大小是在您的测试中人为地施加限制。虽然赋予进程(初始线程)的默认堆栈根据需要动态增长,但其他线程的堆栈大小是固定的。默认大小通常非常大,例如 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);
}

Note that attrs is not consumed by the pthread_create() call. Think of the thread attributes more like a template on how pthread_create() should create the threads; they are not attributes given to the thread. This trips up many aspiring pthreads programmers, so it's one of those things you'd better get right from the get go.

As to the stack size itself, it must be at least PTHREAD_STACK_MIN (16384 in Linux, I believe) and divisible by sysconf(_SC_PAGESIZE). Since page size is a power of two on all architectures, using a large enough power of two should always work.

Also, I added a fix in there, too. You only try to join a nonexistent thread (the one that the loop tried to create, but failed), but you need to join all of them (to make sure they're all done their job).

Further recommended fixes:

Instead of using a sleep, use a condition variable. Have each thread wait (pthread_cond_wait()) on the condition variable (while holding the mutex), then release the mutex and exit. That way your main function only needs to broadcast (pthread_cond_broadcast()) on the condition variable to tell all threads they can now exit, then it can join each one, and you can be sure that that number of threads were really concurrently running. As your code stands now, some threads may have enough time to wake up from the sleep and exit.

于 2012-09-12T23:45:42.837 回答
4

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

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

于 2012-09-12T12:27:22.040 回答
2

根据pthread_create(3)手册页,还有另一个限制:

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-09-12T12:19:26.617 回答