线程栈与地址空间
Linux系统 把所有线程都当做进程来实现,线程作为轻量级进程(LWP)。
线程仅仅被视为一个与其他进程共享某些资源的进程,而 是否共享地址空间几乎是进程和 Linux 中所谓线程的唯一区别 。线程创建的时候,加上了 CLONE_VM 标记,这样  线程的内存描述符 将直接指向 父进程的内存描述符 ,也就是说, 线程的mm_struct *mm指针变量和所属进程的mm指针变量相同。
所有线程都共享一份地址空间,这不但包括text、heap和进程stack等, 甚至还包括了线程stack
注意此处表达的字面意思: 所有线程共享包括线程栈在内的地址空间,并不意味着所有线程都共享一个栈地址,而是一个线程可以访问另一个线程的栈数据 (虽然并没什么用,但确实可行,通过实验可以验证)。显然, 不同线程有不同的函数调用关系所以不能使用同一个栈 。之所以能做到线程A能访问线程B的栈数据,正是因为内核为每个线程在不同地址处分配了栈空间,从进程的全局地址空间看(cat /proc/PID/maps),每个线程的stack都位于不同的地址段。

虽然线程共享地址空间,但线程的私有数据,又是需要单独保存的,这包括了:
  • pthread属性相关,pthread_attr
  • 线程栈,thread stack
  • 线程本地存储,TLS(thread local storage)
这三种数据位于同一块内存中,是在创建线程的时候,用mmap系统调用从heap分配出来的:
这个可以从 glibc 的nptl/allocatestack.c 中的allocate_stack() 函数中看到:
mem = mmap (NULL, size, prot, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);

如何获取线程栈
利用函数pthread_attr_getstack(pthread_t, void** stack_addr, size_t* stack_size);

pid_t __gettid(void) //glibc没有实现gettid()函数,因此我们可以自己实现
{
return syscall(SYS_gettid);
}
void __show_stack(void)
{
size_t stack_size = 0;
void* stackaddr = NULL;
pthread_attr_t attr;
pthread_t pid = pthread_self();
pid_t tid = __gettid();

pthread_attr_init(&attr);
pthread_getattr_np(pid, &attr);//获取当前线程的属性
if(pthread_attr_getstack(&attr, &stackaddr, &stack_size)){
perror("fail to get pthread stack");
}
printf("tid:%d pid:%d stack_addr:%p stack_size:%d \n", tid, pid, stackaddr, stack_size);
}
void* __task(void*arg)
{
__show_stack();
while(1){
sleep(1);
}
}
====================================================================
从如下例子看出,不同线程的stack地址是不一样的。

[lubo@localhost proc]$ ./a.out
tid:7576 pid:-111012032 stack_addr:0x7fff20b58000 stack_size:8380416
tid:7577 pid:-111016192 stack_addr:0x7f55f8e20000 stack_size:8392704
tid:7578 pid:-119408896 stack_addr:0x7f55f861f000 stack_size:8392704
tid:7579 pid:-127801600 stack_addr:0x7f55f7e1e000 stack_size:8392704

[lubo@localhost proc]$ cd /proc/7576
[lubo@localhost 7576]$ cat maps
00400000-00401000 r-xp 00000000 08:07 1848537 /media/work/docs/c_test/pthread/thread_stack/a.out
00601000-00602000 r--p 00001000 08:07 1848537 /media/work/docs/c_test/pthread/thread_stack/a.out
00602000-00603000 rw-p 00002000 08:07 1848537 /media/work/docs/c_test/pthread/thread_stack/a.out
0175b000-0177c000 rw-p 00000000 00:00 0 [heap]
3212800000-3212820000 r-xp 00000000 fd:00 1616273 /usr/lib64/ld-2.18.so
3212a1f000-3212a20000 r--p 0001f000 fd:00 1616273 /usr/lib64/ld-2.18.so
3212a20000-3212a21000 rw-p 00020000 fd:00 1616273 /usr/lib64/ld-2.18.so
3212a21000-3212a22000 rw-p 00000000 00:00 0
3212c00000-3212db4000 r-xp 00000000 fd:00 1616274 /usr/lib64/libc-2.18.so
3212db4000-3212fb4000 ---p 001b4000 fd:00 1616274 /usr/lib64/libc-2.18.so
3212fb4000-3212fb8000 r--p 001b4000 fd:00 1616274 /usr/lib64/libc-2.18.so
3212fb8000-3212fba000 rw-p 001b8000 fd:00 1616274 /usr/lib64/libc-2.18.so
3212fba000-3212fbf000 rw-p 00000000 00:00 0
3213400000-3213418000 r-xp 00000000 fd:00 1616284 /usr/lib64/libpthread-2.18.so
3213418000-3213617000 ---p 00018000 fd:00 1616284 /usr/lib64/libpthread-2.18.so
3213617000-3213618000 r--p 00017000 fd:00 1616284 /usr/lib64/libpthread-2.18.so
3213618000-3213619000 rw-p 00018000 fd:00 1616284 /usr/lib64/libpthread-2.18.so
3213619000-321361d000 rw-p 00000000 00:00 0
7f55e0000000-7f55e0021000 rw-p 00000000 00:00 0
7f55e0021000-7f55e4000000 ---p 00000000 00:00 0
7f55e8000000-7f55e8021000 rw-p 00000000 00:00 0
7f55e8021000-7f55ec000000 ---p 00000000 00:00 0
7f55f0000000-7f55f0021000 rw-p 00000000 00:00 0
7f55f0021000-7f55f4000000 ---p 00000000 00:00 0
7f55f7e1e000-7f55f7e1f000 ---p 00000000 00:00 0
7f55f7e1f000-7f55f861f000 rw-p 00000000 00:00 0 [stack:7579]
7f55f861f000-7f55f8620000 ---p 00000000 00:00 0
7f55f8620000-7f55f8e20000 rw-p 00000000 00:00 0 [stack:7578]
7f55f8e20000-7f55f8e21000 ---p 00000000 00:00 0
7f55f8e21000-7f55f9624000 rw-p 00000000 00:00 0 [stack:7577]
7f55f9650000-7f55f9652000 rw-p 00000000 00:00 0
7fff21337000-7fff21358000 rw-p 00000000 00:00 0 [stack]
7fff213fe000-7fff21400000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]


例子代码(fedora22/x86及mips/uclibc都能跑通)见附件
pthread_stack.c

Logo

更多推荐