天天看點

thread線程棧size及局部變量最大可配置設定size【轉】

版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。

程序是作業系統的最小資源管理單元, 線程是作業系統最小的執行單元。 一個程序可以有多個線程, 也就是說多個線程分享程序的資源,包括棧區,堆區,代碼區,資料區等。

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  

32bit x86機器上面,執行ulimit -a的指令, 可以看到 

stack size              (kbytes, -s) 8192    這是否說明線上程中可以配置設定8M的局部變量(或者說配置設定7M的局部變量,還有1M的空間存儲其他的局部變量或者寄存器狀态資訊(例如bp等)或者函數壓棧資訊等)

寫代碼驗證如下:

//test2.cpp  

#include <iostream>  

#include <string.h>  

#include <pthread.h>  

#include <stdio.h>  

using namespace std;  

void* func(void*a)  

{  

    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 <http://gnu.org/licenses/gpl.html>

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:

<http://www.gnu.org/software/gdb/bugs/>...

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.5M的局部變量,是不會報錯的, 但子線程中配置設定2M的局部變量,就會coredump。 可見,隻能配置設定不大于2M的局部變量,但ulimit -a 查詢到的stack size 為8M。

猜想:  線程隻能配置設定不大于 1/4 大小的 stack size 給 局部變量, 這應該是作業系統的規定。(沒在網絡上面找到相關的文檔說明)

那我們現在開始驗證我們的猜想:

通過 ulimit -s指令修改預設的棧大小,  下面程式配置設定5M的局部變量, 也就是說線程棧的大小要 > 20M(5M*4)

//test1.cpp  

    int b[1024*1024*5] = {0};  

    int a[1024*1024*5]={0};  

ulimit -s 21504 (也就是21M) , 把預設的stack size設定為21M

sundh@linux:~ulimit−s21504sundh@linux: ulimit−s21504sundh@linux:  g++ -g -o test2 test2.cpp -lpthread

sundh@linux:~$ ./test2

This is a testenter func

enter func

可以成功運作, 驗證了我們的猜想。

ulimit -s 修改 stack size, 也可以通過 pthread_attr_setstacksize() 來修改。 使用ulimit的一個後果就是它會影響到同一環境(同一shell或者終端)下後續啟動的所有程式,如果修改成啟動時設定的話就會影響到整個系統。 是以大部分情況下還是使用pthread_attr_setstacksize()

代碼如下:

#include <stdlib.h>  

#include <unistd.h>  

#include <errno.h>  

#include <ctype.h>  

#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;  

     <span style="color:#FF0000;">int a[1024*1024*5] = {0};</span>  

 printf("Thread %d: top of stack near %p; argv_string=%s\n",  

            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...\n",  

                    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 = <span style="color:#FF0000;">pthread_attr_setstacksize</span>(&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]);  

            handle_error_en(s, "pthread_create");  

   /* Destroy the thread attributes object, since it is no 

       longer needed */  

   s = pthread_attr_destroy(&attr);  

        handle_error_en(s, "pthread_attr_destroy");  

   /* Now join with each thread, and display its returned value */  

        s = pthread_join(tinfo[tnum].thread_id, &res);  

            handle_error_en(s, "pthread_join");  

       printf("Joined with thread %d; returned value was %s\n",  

                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,也即8M, 不能在main() 裡面聲明超過2M的局部變量,建立子線程的時候調用了pthread_attr_setstacksize(), 修改stack size為21M,然後就能在子線程中聲明5M的局部變量了。

本文轉自張昺華-sky部落格園部落格,原文連結:http://www.cnblogs.com/sky-heaven/p/7654950.html,如需轉載請自行聯系原作者

繼續閱讀