8. スレッド属性(スレッド数)
8.4 起動スレッド数との関連
どんなに贅沢な環境であっても、メモリは有限です。有限である以上、プロセスが使用できるメモリ量はスタックに上限があります。
カーネルでは10,000個以上のスタックを生成できる設定になっていてもメモリが十分でなければ生成スレッド数はそれ以下になります。スレッドが起動できない理由はエラーコードから判定することができます。
- エラーコードが11(Resource temporarily unavailable)
- エラーコードが12(Cannot allocate memory)
以下のサンプルを起動する事で、スタックサイズの遷移によって起動可能スレッド数が変わっていくのが判ると思います。
/* gcc stack_thread.c -o stack_thread -W -Wall -g -lpthread */ #include <stdio.h> #include <string.h> #include <pthread.h> #include <errno.h> #include <unistd.h> #include <limits.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; void create_thread( size_t size ); void * thread_func( void * arg ); int main( ) { pthread_attr_t attr; size_t stack_size = 0; pthread_attr_init( &attr ); pthread_attr_getstacksize( &attr, &stack_size ); create_thread( PTHREAD_STACK_MIN ); create_thread( PTHREAD_STACK_MIN * 4 ); create_thread( stack_size ); create_thread( stack_size * 32 ); create_thread( stack_size * 128 ); create_thread( stack_size * 256 ); return 0; } void create_thread( size_t size ) { pthread_attr_t attr; pthread_t id; int status = 0; int i = 0; pthread_attr_init( &attr ); pthread_attr_setstacksize( &attr, size ); for( i = 0; ; i ++ ) { status = pthread_create( &id, &attr, thread_func, ( void * )&i ); if( status ) { pthread_cond_broadcast( &cond ); break; } } printf( "stack size %zd[%zdK], total size %zd[%zdM], " "total thread_count %d\n", size, size >> 10, size * i, ( size * i ) >> 20, i ); printf( " pthread_create error. [%d][%s]\n", status, strerror( status )); pthread_attr_destroy( &attr ); sleep( 1 ); return; } void * thread_func( void * arg ) { ( void )arg; pthread_detach( pthread_self( )); pthread_mutex_lock( &mutex ); pthread_cond_wait( &cond, &mutex ); pthread_mutex_unlock( &mutex ); return 0; }
私の環境では、下記の通りとなりました。
guest $ ./stack_thread stack size 16384[16k], total size 200163328[190M],total thread_count 12217 pthread_create error. [11][Resource temporarily unavailable] stack size 65536[64k], total size 800653312[763M],
total thread_count 12217 pthread_create error. [11][Resource temporarily unavailable] stack size 10485760[10240k], total size -1149239296[3000M],
total thread_count 300 pthread_create error. [12][Cannot allocate memory] stack size 335544320[327680k], total size -1610612736[2560M],
total thread_count 8 pthread_create error. [12][Cannot allocate memory] stack size 671088640[655360k], total size 2013265920[1920M],
total thread_count 3 pthread_create error. [12][Cannot allocate memory] stack size 1342177280[1310720k], total size 1342177280[1280M],
total thread_count 1 pthread_create error. [12][Cannot allocate memory] guest $ guest $ cat /proc/sys/kernel/threads-max 24572 guest $
上記から、私の環境ではスタックサイズを16~64Kくらいだと、threads-maxの半値、つまり生成スレッドの最大値になります。デフォルトのスタックサイズではスレッド数は300個、スタックサイズを320Mまであげると8個、1.2Gまで上げると3個です。
8.5 所感
以上でスレッド属性の簡単な説明を終えます。スタックサイズを小さくして大量のスレッドを生成する場合、スタックのデフォルト値でスレッドの上限値に達するような環境の場合は、その効果は期待できません(私の環境では大いに改善しましたが)。
スレッド内で大量のメモリを消費する可能性がある場合、もしくはスタックサイズを縮める事で起動可能スレッド数を増やしたい場合に使用のが良いでしょう(それ以前にメモリを積めって話もありますが…)。
次回はスレッド属性におけるスケジューリングとその影響について述べます。

total thread_count 12217
pthread_create error. [11][Resource temporarily unavailable]
stack size 65536[64k], total size 800653312[763M],