我在ubuntu 9.04,gcc4.4.1环境下进行该实验,证明线程的栈确实有固定大小,也就是ulimit -a显示的那个值,在我的实验室环境下为8M字节
实验1:
#include <stdio.h>
#include <pthread.h>
int i = 0;
void *test(void * s) {
int buffer[1024];
printf("i=%d\n", i);
i++;
test(s);
}
int main() {
pthread_t p;
pthread_create(&p, NULL, &test, NULL);
sleep(100);
}
结果在i=2029之后出现断错误
并且可以使用如下代码修改这个线程栈的大小为16M:
实验2:
#include <stdio.h>
#include <pthread.h>
int i = 0;
void *test(void * s) {
int buffer[1024];
printf("i=%d\n", i);
i++;
test(s);
}
int main() {
pthread_t p;
pthread_attr_t tattr;
void *stack;
pthread_attr_init(&tattr);
stack=malloc(16*1024*1024);
pthread_attr_setstack(&tattr,stack,16*1024*1024); //注意这个空间应该从堆中分配,如果从栈中分配,就会出现另一个问题,我们后面会提到
pthread_create(&p, &tattr, &test, NULL);
sleep(100);
}
结果在4062时出现断错误
但是如果用两个线程使用默认大小,来进行上面的实验,两个栈的总和并不是一个线程的二倍,并且这个总和也不是固定值
实验3:
#include <stdio.h>
#include <pthread.h>
int i = 0;
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
void *test(void * s) {
int buffer[1024];
pthread_mutex_lock(&mutex);
printf("i=%d\n", i);
i++;
pthread_mutex_unlock(&mutex);
test(s);
}
int main() {
pthread_t p1,p2;
pthread_create(&p1, NULL, &test, NULL);
pthread_create(&p2, NULL, test, NULL);
sleep(100);
}
结果为3740
如果不使用任何线程的话,那么一个进程的栈也不是理论上的2G,而是比一个线程的栈稍(ulimit -a 的值8M)大一些,并且这个栈的大小也不总是固定的
实验4:
#include <stdio.h>
int i=0;
void fun()
{
int buffer[1024];
printf("i=%d\n",i);
i++;
fun();
}
int main()
{
fun();
sleep(100);
}
如果pthread_attr_setstack设置的线程栈是从栈空间分配的话,如果线程栈的大小为8M的话,那么线程栈的大小也不是固定不变了而是和实验4的结果相同(类似?)
如果线程栈大小为9M的话,那么线程栈的大小也不是固定不变,但这个时候有可能在进程一开始的时候就发生段错误,即使是同一个可执行文件多次不同执行也会出现这种现象,说明这个栈的大小是和gcc的编译与链接无关的
实验5:
#include <stdio.h>
#include <pthread.h>
int i = 0;
void *test(void * s) {
int buffer[1024];
printf("i=%d\n", i);
i++;
test(s);
}
int main() {
pthread_t p;
pthread_attr_t tattr;
char stack[9*1024*1024];
pthread_attr_init(&tattr);
pthread_attr_setstack(&tattr,&stack[0],9*1024*1024);
pthread_create(&p, &tattr, &test, NULL);
sleep(100);
}
结论:
1. 进程的栈大小是在进程执行的时刻才能指定的,即不是在编译的时刻决定,也不是链接的时刻决定,否则就不会有实验5的结果
2. 进程的栈大小是随机确定的至少比线程的栈要大,但是不到线程栈大小的2倍
3. 线程栈的大小是固定的,也就是ulimit -a显示的值