我编写了一个简单的程序来计算进程在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作为错误代码。
之前谢谢
答案 0 :(得分:17)
Linux的线程限制,可以通过将所需的限制写入/proc/sys/kernel/threads-max
来修改运行时。默认值从可用系统内存计算。除了该限制之外,还有另一个限制:/proc/sys/vm/max_map_count
限制了最大mmapped段,并且至少最近的内核将为每个线程mmap内存。如果你点击它会增加这个限制应该是安全的。
在32位操作系统中,你所遇到的限制是缺少虚拟内存。如果你的硬件支持它,安装64位Linux,你会没事的。我可以轻松启动30000个堆栈大小为8MB的线程。该系统有一个Core 2 Duo + 8 GB的系统内存(我在同一时间使用5 GB用于其他内容)并且它运行64位Ubuntu和内核2.6.32。请注意,必须允许内存过量使用(/ proc / sys / vm / overcommit_memory),否则系统将需要至少240 GB的可提交内存(实际内存和交换空间的总和)。
如果您需要大量线程且无法使用64位系统,您唯一的选择是最小化每个线程的内存使用量以节省虚拟内存。首先请求尽可能少的堆栈。
答案 1 :(得分:6)
您的系统限制可能不允许您映射所需的所有线程的堆栈。查看/proc/sys/vm/max_map_count
,然后查看this answer。我不是100%确定这是你的问题,因为大多数人在much larger thread counts遇到问题。
答案 2 :(得分:4)
当我的线程数超过某个阈值时,我也遇到了同样的问题。 这是因为/etc/security/limits.conf中的用户级别限制(用户可以一次运行的进程数)设置为1024。
请检查您的/etc/security/limits.conf并查找条目: -
用户名 - / soft / hard -nproc 1024
将它更改为更大的值到100k(需要sudo权限/ root),它应该适合你。
要详细了解安全政策,请参阅http://linux.die.net/man/5/limits.conf。
答案 3 :(得分:3)
使用ulimit检查每个线程的堆栈大小,在我的例子中是Redhat Linux 2.6:
ulimit -a
...
stack size (kbytes, -s) 10240
每个线程都会为它的堆栈分配这个内存量(10MB)。使用32位程序,最大地址空间为4GB,最大只有4096MB / 10MB = 409个线程!减去程序代码,减去堆空间可能会导致您观察到的最大值。 300个主题。
您应该能够通过编译64位应用程序或设置ulimit -s 8192甚至ulimit -s 4096来提高这一点。但如果这是可取的另一个讨论...
答案 4 :(得分:1)
除非你缩小默认的线程堆栈大小,否则你的内存也会耗尽。在我们的linux版本上它的10MB。
修改强> 错误代码12 =内存不足,所以我认为1mb堆栈对你来说仍然太大了。编译为32位,我可以得到一个100k堆栈给我30k线程。超过30k线程我得到错误代码11,这意味着不再允许线程。 1MB的堆栈在错误代码12之前给了我大约4k个线程.10MB给了我427个线程。 100MB给了我42个线程。 1 GB给了我4 ...我们有64位操作系统和64 GB RAM。你的OS是32位吗?当我编译64位时,我可以使用我想要的任何堆栈大小并获得线程限制。
另外我注意到如果我打开netbeans的分析内容(工具|分析)并从ide运行...我只能获得400个线程。奇怪的。如果你用尽所有线程,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;
}