threadスレッドスタックsizeおよびローカル変数最大割り当て可能size

8437 ワード

プロセスはオペレーティングシステムの最小リソース管理ユニットであり、スレッドはオペレーティングシステムの最小実行ユニットである.1つのプロセスには、スタック領域、スタック領域、コード領域、データ領域など、複数のスレッドがプロセスのリソースを共有することができる.
sundh@linhaoIPTV:~$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 31675
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 31675
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

32 bit x 86マシン上で、ulimit-aのコマンドを実行すると、
stack size(kbytes,-s)8192これは、スレッドに8 Mのローカル変数(あるいは7 Mのローカル変数を割り当てることができ、また1 Mの空間が他のローカル変数やレジスタ状態情報(例えばbpなど)や関数スタック情報などを格納することができることを示しているかどうかを示す.
//test2.cpp
#include 
#include 
#include 
#include 

using namespace std;

void* func(void*a)
{
    cout << "enter func" << endl;
    cout << "enter func" << endl;
    int b[1024*1024*2] = {0};
}

int main()
{
    int a[1024*1024*3/2]={0};
    pthread_t  pthread ;
    pthread_create(&pthread, NULL, func, NULL);
    cout << "This is a test" << endl;
    //pthread_join(pthread, NULL);
    return 0;
}
g++ -g -o test2 test2.cpp -lpthread
sundh@linux:~$ gdb test2
GNU gdb (GDB) 7.5-ubuntu
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty"for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
...
Reading symbols from/home/sundh/test2...done.
(gdb) r
Starting program:/home/sundh/test2
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
[New Thread 0xb7cc1b40 (LWP 10313)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb7cc1b40 (LWP 10313)]
func (a=0x0) at test2.cpp:10
10          cout << "enter func"<< endl;
(gdb)
GDBのデバッグ結果は上記の通りです.main()関数に1.5 Mのローカル変数を割り当てると、エラーは報告されませんが、サブスレッドに2 Mのローカル変数を割り当てるとcoredumpになります.2 M以下のローカル変数しか割り当てられませんが、ulimit-aでクエリされたstack sizeは8 Mです.
スレッドは、ローカル変数に1/4未満のstack sizeしか割り当てられません.これはオペレーティングシステムの規定です.(ネットワーク上に関連するドキュメントの説明が見つかりません)
では、私たちの推測を検証し始めます.
デフォルトのスタックサイズをulimit-sコマンドで変更します.次のプログラムでは、5 Mのローカル変数を割り当てます.つまり、スレッドスタックのサイズは>20 M(5 M*4)です.
//test1.cpp
#include 
#include 
#include 
#include 

using namespace std;

void* func(void*a)
{
    cout << "enter func" << endl;
    cout << "enter func" << endl;
    int b[1024*1024*5] = {0};
}

int main()
{
    int a[1024*1024*5]={0};
    pthread_t  pthread ;
    pthread_create(&pthread, NULL, func, NULL);
    cout << "This is a test" << endl;
    //pthread_join(pthread, NULL);
    return 0;
}

ulimit-s 21504(つまり21 M)、デフォルトのstack sizeを21 Mに設定
sundh@linux:~$ ulimit -s 21504 sundh@linux:~$ g++ -g -o test2 test2.cpp -lpthread sundh@linux:~$ ./test 2 This a testenter func enter funcは正常に動作し,我々の推測を検証した.
ulimit-s stack sizeを変更してもpthread_attr_setstacksize()で変更します.ulimitを使用すると、同じ環境(同じshellまたは端末)で後続に起動するすべてのプログラムに影響し、起動時の設定に変更するとシステム全体に影響します.ほとんどの場合pthread_を使用しますattr_setstacksize()
コードは次のとおりです.
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define handle_error_en(en, msg) \
        do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

#define handle_error(msg) \
        do { perror(msg); exit(EXIT_FAILURE); } while (0)

struct thread_info {    /* Used as argument to thread_start() */
    pthread_t thread_id;        /* ID returned by pthread_create() */
    int       thread_num;       /* Application-defined thread # */
    char     *argv_string;      /* From command-line argument */
};

/* Thread start function: display address near top of our stack,
   and return upper-cased copy of argv_string */

static void *
thread_start(void *arg)
{
    struct thread_info *tinfo = arg;
    char *uargv, *p;

     int a[1024*1024*5] = {0};
 printf("Thread %d: top of stack near %p; argv_string=%s
", tinfo->thread_num, &p, tinfo->argv_string); uargv = strdup(tinfo->argv_string); if (uargv == NULL) handle_error("strdup"); for (p = uargv; *p != '\0'; p++) *p = toupper(*p); return uargv; } int main(int argc, char *argv[]) { int s, tnum, opt, num_threads; struct thread_info *tinfo; pthread_attr_t attr; int stack_size; void *res; /* The "-s" option specifies a stack size for our threads */ stack_size = -1; while ((opt = getopt(argc, argv, "s:")) != -1) { switch (opt) { case 's': stack_size = strtoul(optarg, NULL, 0); break; default: fprintf(stderr, "Usage: %s [-s stack-size] arg...
", argv[0]); exit(EXIT_FAILURE); } } num_threads = argc - optind; /* Initialize thread creation attributes */ s = pthread_attr_init(&attr); if (s != 0) handle_error_en(s, "pthread_attr_init"); if (stack_size > 0) { s = pthread_attr_setstacksize(&attr, stack_size); if (s != 0) handle_error_en(s, "pthread_attr_setstacksize"); } /* Allocate memory for pthread_create() arguments */ tinfo = calloc(num_threads, sizeof(struct thread_info)); if (tinfo == NULL) handle_error("calloc"); /* Create one thread for each command-line argument */ for (tnum = 0; tnum < num_threads; tnum++) { tinfo[tnum].thread_num = tnum + 1; tinfo[tnum].argv_string = argv[optind + tnum]; /* The pthread_create() call stores the thread ID into corresponding element of tinfo[] */ s = pthread_create(&tinfo[tnum].thread_id, &attr, &thread_start, &tinfo[tnum]); if (s != 0) handle_error_en(s, "pthread_create"); } /* Destroy the thread attributes object, since it is no longer needed */ s = pthread_attr_destroy(&attr); if (s != 0) handle_error_en(s, "pthread_attr_destroy"); /* Now join with each thread, and display its returned value */ for (tnum = 0; tnum < num_threads; tnum++) { s = pthread_join(tinfo[tnum].thread_id, &res); if (s != 0) handle_error_en(s, "pthread_join"); printf("Joined with thread %d; returned value was %s
", tinfo[tnum].thread_num, (char *) res); free(res); /* Free memory allocated by thread */ } free(tinfo); exit(EXIT_SUCCESS); }

$ ./a.out -s 0x1600000 hola salut servus   (0x1500000  == 20M,0x1600000==21M  )
Thread 1: top of stack near 0xb7d723b8; argv_string=hola
Thread 2: top of stack near 0xb7c713b8; argv_string=salut
Thread 3: top of stack near 0xb7b703b8; argv_string=servus
Joined with thread 1; returned value was HOLA
Joined with thread 2; returned value was SALUT
Joined with thread 3; returned value was SERVUS
プログラムは正常に動作します.ここで注意しなければならないのは、メインスレッドがシステムのデフォルトのstack size、すなわち8 Mを使用するか、main()に2 Mを超えるローカル変数を宣言することはできず、サブスレッドを作成するときにpthread_を呼び出すことです.attr_setstacksize()を設定し、stack sizeを21 Mに変更すると、サブスレッドで5 Mのローカル変数を宣言できます.