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を返すことを言及する必要があります。
前に感謝します
linuxのスレッド制限があり、必要な制限を/proc/sys/kernel/threads-max
に書き込むことで実行時に変更できます。デフォルト値は、使用可能なシステムメモリから計算されます。その制限に加えて、別の制限もあります。/proc/sys/vm/max_map_count
は、最大のmmapセグメントを制限し、少なくとも最近のカーネルはスレッドごとにメモリをmmapします。あなたがそれに当たった場合、その制限をたくさん増やすことは安全であるはずです。
あなたが打っている限界は仮想メモリの不足です 32ビットオペレーティングシステムで。ハードウェアが64ビットLinuxをサポートしていれば、問題はありません。スタックサイズ8MBで30000スレッドを簡単に開始できます。システムには単一のCore2 Duo + 8 GBのシステムメモリがあり(私は同時に他のものに5 GBを使用しています)、カーネル2.6.32で64ビットUbuntuを実行しています。メモリのオーバーコミット(/ proc/sys/vm/overcommit_memory)を許可する必要があることに注意してください。許可しない場合、システムには少なくとも240 GBのコミット可能なメモリ(実メモリとスワップスペースの合計)が必要になります。
多数のスレッドが必要で、64ビットシステムを使用できない場合は、スレッドあたりのメモリ使用量を最小限に抑えて仮想メモリを節約するしかありません。できるだけ少ないスタックを要求することから始めます。
システムの制限により、必要なすべてのスレッドのスタックをマップできない場合があります。見る /proc/sys/vm/max_map_count
、および この回答 を参照してください。ほとんどの人が スレッド数がはるかに多い で問題に遭遇するため、これがあなたの問題であるかどうかは100%わかりません。
スレッドの数があるしきい値を超えたときにも同じ問題が発生しました。これは、/ etc/security/limits.confでユーザーレベルの制限(ユーザーが一度に実行できるプロセスの数)が1024に設定されているためです。
/etc/security/limits.confを確認して、エントリを探してください:-
ユーザー名-/ soft/hard -nproc 1024
それをいくつかのより大きな値に100k(Sudo特権/ rootが必要)に変更すると、うまくいくはずです。
セキュリティポリシーの詳細については、 http://linux.die.net/man/5/limits.conf を参照してください。
ulimitを使用してスレッドあたりのスタックサイズを確認します。私の場合はRedhatLinux2.6です。
ulimit -a
...
stack size (kbytes, -s) 10240
各スレッドは、そのスタックに割り当てられたこの量のメモリ(10MB)を取得します。 32ビットプログラムと4GBの最大アドレス空間では、最大で4096MB/10MB = 409スレッドになります!!!マイナスのプログラムコードからヒープスペースを引いたものが、おそらく観測された最大値につながります。 300スレッドの。
64ビットアプリケーションをコンパイルするか、ulimit -s8192またはulimit-s 4096を設定することで、これを上げることができるはずです。しかし、これが推奨される場合は、別の議論があります...
デフォルトのスレッドスタックサイズを縮小しない限り、メモリも不足します。私たちのバージョンのLinuxでは10MBです。
編集:エラーコード12 =メモリ不足なので、1MBのスタックはまだ大きすぎると思います。 32ビット用にコンパイルすると、100kスタックを取得して30kスレッドを取得できます。 30kスレッドを超えると、エラーコード11が発生します。これは、スレッドが許可されないことを意味します。 1MBのスタックではエラーコード12の前に約4kスレッドが得られます。10MBでは427スレッドが得られます。 100MBで42スレッドになります。 1GBは私に4を与えます...私たちは64GBのRAMを備えた64ビットOSを持っています。 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;
}