thread线程栈size及局部变量最大可分配size【转】

简介:

转自:http://blog.csdn.net/sunny04/article/details/46805261

进程是操作系统的最小资源管理单元, 线程是操作系统最小的执行单元。 一个进程可以有多个线程, 也就是说多个线程分享进程的资源,包括栈区,堆区,代码区,数据区等。

[cpp]  view plain  copy
  1. sundh@linhaoIPTV:~$ ulimit -a  
  2. core file size          (blocks, -c) 0  
  3. data seg size           (kbytes, -d) unlimited  
  4. scheduling priority             (-e) 0  
  5. file size               (blocks, -f) unlimited  
  6. pending signals                 (-i) 31675  
  7. max locked memory       (kbytes, -l) 64  
  8. max memory size         (kbytes, -m) unlimited  
  9. open files                      (-n) 1024  
  10. pipe size            (512 bytes, -p) 8  
  11. POSIX message queues     (bytes, -q) 819200  
  12. real-time priority              (-r) 0  
  13. stack size              (kbytes, -s) 8192  
  14. cpu time               (seconds, -t) unlimited  
  15. max user processes              (-u) 31675  
  16. virtual memory          (kbytes, -v) unlimited  
  17. file locks                      (-x) unlimited  

 

32bit x86机器上面,执行ulimit -a的命令, 可以看到 

stack size              (kbytes, -s) 8192    这是否说明在线程中可以分配8M的局部变量(或者说分配7M的局部变量,还有1M的空间存储其他的局部变量或者寄存器状态信息(例如bp等)或者函数压栈信息等)

写代码验证如下:

[cpp]  view plain  copy
  1. //test2.cpp  
  2. #include <iostream>  
  3. #include <string.h>  
  4. #include <pthread.h>  
  5. #include <stdio.h>  
  6.   
  7. using namespace std;  
  8.   
  9. void* func(void*a)  
  10. {  
  11.     cout << "enter func" << endl;  
  12.     cout << "enter func" << endl;  
  13.     int b[1024*1024*2] = {0};  
  14. }  
  15.   
  16. int main()  
  17. {  
  18.     int a[1024*1024*3/2]={0};  
  19.     pthread_t  pthread ;  
  20.     pthread_create(&pthread, NULL, func, NULL);  
  21.     cout << "This is a test" << endl;  
  22.     //pthread_join(pthread, NULL);  
  23.     return 0;  
  24. }  

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)

[cpp]  view plain  copy
  1. //test1.cpp  
  2. #include <iostream>  
  3. #include <string.h>  
  4. #include <pthread.h>  
  5. #include <stdio.h>  
  6.   
  7. using namespace std;  
  8.   
  9. void* func(void*a)  
  10. {  
  11.     cout << "enter func" << endl;  
  12.     cout << "enter func" << endl;  
  13.     int b[1024*1024*5] = {0};  
  14. }  
  15.   
  16. int main()  
  17. {  
  18.     int a[1024*1024*5]={0};  
  19.     pthread_t  pthread ;  
  20.     pthread_create(&pthread, NULL, func, NULL);  
  21.     cout << "This is a test" << endl;  
  22.     //pthread_join(pthread, NULL);  
  23.     return 0;  
  24. }  

ulimit -s 21504 (也就是21M) , 把默认的stack size设置为21M

sundh@linux:~ulimits21504sundh@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()

代码如下:

[cpp]  view plain  copy
  1. #include <pthread.h>  
  2. #include <string.h>  
  3. #include <stdio.h>  
  4. #include <stdlib.h>  
  5. #include <unistd.h>  
  6. #include <errno.h>  
  7. #include <ctype.h>  
  8.   
  9. #define handle_error_en(en, msg) \  
  10.         do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)  
  11.   
  12. #define handle_error(msg) \  
  13.         do { perror(msg); exit(EXIT_FAILURE); } while (0)  
  14.   
  15. struct thread_info {    /* Used as argument to thread_start() */  
  16.     pthread_t thread_id;        /* ID returned by pthread_create() */  
  17.     int       thread_num;       /* Application-defined thread # */  
  18.     char     *argv_string;      /* From command-line argument */  
  19. };  
  20.   
  21. /* Thread start function: display address near top of our stack, 
  22.    and return upper-cased copy of argv_string */  
  23.   
  24. static void *  
  25. thread_start(void *arg)  
  26. {  
  27.     struct thread_info *tinfo = arg;  
  28.     char *uargv, *p;  
  29.   
  30.      <span style="color:#FF0000;">int a[1024*1024*5] = {0};</span>  
  31.  printf("Thread %d: top of stack near %p; argv_string=%s\n",  
  32.             tinfo->thread_num, &p, tinfo->argv_string);  
  33.   
  34.    uargv = strdup(tinfo->argv_string);  
  35.     if (uargv == NULL)  
  36.         handle_error("strdup");  
  37.   
  38.    for (p = uargv; *p != '\0'; p++)  
  39.         *p = toupper(*p);  
  40.   
  41.    return uargv;  
  42. }  
  43.   
  44. int  
  45. main(int argc, char *argv[])  
  46. {  
  47.     int s, tnum, opt, num_threads;  
  48.     struct thread_info *tinfo;  
  49.     pthread_attr_t attr;  
  50.     int stack_size;  
  51.     void *res;  
  52.   
  53.    /* The "-s" option specifies a stack size for our threads */  
  54.   
  55.    stack_size = -1;  
  56.     while ((opt = getopt(argc, argv, "s:")) != -1) {  
  57.         switch (opt) {  
  58.         case 's':  
  59.             stack_size = strtoul(optarg, NULL, 0);  
  60.             break;  
  61.   
  62.        default:  
  63.             fprintf(stderr, "Usage: %s [-s stack-size] arg...\n",  
  64.                     argv[0]);  
  65.             exit(EXIT_FAILURE);  
  66.         }  
  67.     }  
  68.   
  69.    num_threads = argc - optind;  
  70.   
  71.    /* Initialize thread creation attributes */  
  72.   
  73.    s = pthread_attr_init(&attr);  
  74.     if (s != 0)  
  75.         handle_error_en(s, "pthread_attr_init");  
  76.   
  77.    if (stack_size > 0) {  
  78.         s = <span style="color:#FF0000;">pthread_attr_setstacksize</span>(&attr, stack_size);  
  79.         if (s != 0)  
  80.             handle_error_en(s, "pthread_attr_setstacksize");  
  81.     }  
  82.   
  83.    /* Allocate memory for pthread_create() arguments */  
  84.   
  85.    tinfo = calloc(num_threads, sizeof(struct thread_info));  
  86.     if (tinfo == NULL)  
  87.         handle_error("calloc");  
  88.   
  89.    /* Create one thread for each command-line argument */  
  90.   
  91.    for (tnum = 0; tnum < num_threads; tnum++) {  
  92.         tinfo[tnum].thread_num = tnum + 1;  
  93.         tinfo[tnum].argv_string = argv[optind + tnum];  
  94.   
  95.        /* The pthread_create() call stores the thread ID into 
  96.            corresponding element of tinfo[] */  
  97.   
  98.        s = pthread_create(&tinfo[tnum].thread_id, &attr,  
  99.                            &thread_start, &tinfo[tnum]);  
  100.         if (s != 0)  
  101.             handle_error_en(s, "pthread_create");  
  102.     }  
  103.   
  104.    /* Destroy the thread attributes object, since it is no 
  105.        longer needed */  
  106.   
  107.    s = pthread_attr_destroy(&attr);  
  108.     if (s != 0)  
  109.         handle_error_en(s, "pthread_attr_destroy");  
  110.   
  111.    /* Now join with each thread, and display its returned value */  
  112.   
  113.    for (tnum = 0; tnum < num_threads; tnum++) {  
  114.         s = pthread_join(tinfo[tnum].thread_id, &res);  
  115.         if (s != 0)  
  116.             handle_error_en(s, "pthread_join");  
  117.   
  118.        printf("Joined with thread %d; returned value was %s\n",  
  119.                 tinfo[tnum].thread_num, (char *) res);  
  120.         free(res);      /* Free memory allocated by thread */  
  121.     }  
  122.   
  123.    free(tinfo);  
  124.     exit(EXIT_SUCCESS);  
  125. }  

./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,如需转载请自行联系原作者

相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
相关文章
|
25天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
116 9
|
16天前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
22 1
|
3天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
23 5
|
19天前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
5天前
|
存储 安全 Java
深入理解ThreadLocal:线程局部变量的机制与应用
在多线程编程中,`ThreadLocal`变量提供了一种线程安全的解决方案,允许每个线程拥有自己的变量副本,从而避免了线程间的数据竞争。本文将详细介绍`ThreadLocal`的工作原理、使用方法以及在实际开发中的应用场景。
15 3
|
22天前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
24天前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
47 4
|
28天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
2月前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
20 3
|
2月前
|
Java
在Java多线程编程中,实现Runnable接口通常优于继承Thread类
【10月更文挑战第20天】在Java多线程编程中,实现Runnable接口通常优于继承Thread类。原因包括:1) Java只支持单继承,实现接口不受此限制;2) Runnable接口便于代码复用和线程池管理;3) 分离任务与线程,提高灵活性。因此,实现Runnable接口是更佳选择。
37 2