轉自:http://blog.csdn.net/sunny04/article/details/46805261
版權聲明:本文為博主原創文章,未經博主允許不得轉載。
進程是操作系統的最小資源管理單元, 線程是操作系統最小的執行單元。 一個進程可以有多個線程, 也就是說多個線程分享進程的資源,包括棧區,堆區,代碼區,數據區等。
- 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;??
- ????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??
- #include?<iostream>??
- #include?<string.h>??
- #include?<pthread.h>??
- #include?<stdio.h>??
- ??
- 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 (也就是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?<pthread.h>??
- #include?<string.h>??
- #include?<stdio.h>??
- #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]);??
- ????????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\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,如需轉載請自行聯系原作者