在创建线程的时候,可以通过pthread_attr_t来初始化线程的属性,包括线程的栈布局信息,如栈起始地址stackaddr,栈大小stacksize。 具体需要通过方法

int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
// 注:stackaddr 指向为该线程开辟的空间,该空间可以使用malloc或者mmap来开辟,而不能来自进程的栈区。开辟的stackaddr所指向的动态空间需要自己负责释放。

  当然也可将线程栈的空间管理交给系统,如果想改变系统默认的栈大小8MB,可以通过

int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
// 注:stacksize小值为16384,单位为字节

  由上面的API接口,可以得到,线程栈的stacksize是保存在pthread_attr_t中的,可以通过人为的指定,也可以通过在创建线程的时候读取系统的配置文件来初始化stacksize,当初始化完栈的起始地址,和大小后,便可以通过

int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);

  来初始化线程栈末尾之后用以避免栈溢出的缓冲区的大小,如果应用程序溢出到此缓冲区中,这个错误可能会导致 SIGSEGV 信号被发送给该线程, 从而造成段错误,缓冲区默认设置为PAGESIZE个字节。因为线程的mm->start_stack和所属进程相同,所以线程栈的起始地址并没有存放在task_struct中,应该只是使用attr中的stackaddr,来初始化task_struct->thread-> sp(sp指向struct pt_regs对象,该结构体用于保存用户进程或者线程的寄存器现场)。

  总结:线程栈的空间开辟在所属进程的堆区,线程与其所属的进程共享进程的用户空间,所以线程栈之间可以互访。线程栈的起始地址和大小存放在pthread_attr_t 中,栈的大小并不是用来判断栈是否越界,而是用来初始化避免栈溢出的缓冲区的大小(或者说安全间隙的大小)

  ps:文中如有错误的地方,请各位随时提出来,我将第一时间更改,谢谢。