Linux下线程中栈变量和堆变量的共享性

在 CSAPP 中,说到在操作系统的线程概念模型中,每个线程有独立的栈,而线程之间不能访问其他栈的变量。

概念模型

线程独享有:

  • 线程 ID
  • 栈指针
  • PC 程序计数器
  • 条件状态位
  • 寄存器

不独享的有:

  • 指令代码
  • .data
  • shared library

但是在实际的实现中,事情会变得不一样。

实际实现

线程实际独立的东西只有:

  • 线程 ID
  • PC 程序计数器
  • 栈指针
  • 寄存器
  • 条件状态位

而且线程之间的栈可以互相访问。

为了探究这一特性,做了相关的测试代码。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/*
* 创建两个全局指针 a,b,首先由 线程 1 修改两个指针分别指向堆变量和栈变量
* 线程 2 分别访问两个指针指向的地址,检验堆变量和栈变量的可访问性
*/

#include <dbg.h>
#include <pthread.h>

int* a = nullptr;
int *b = nullptr;

void* fun1(void*) {
    sleep(1);
    dbg("------1s------");

    dbg(a = new int(1000));
    int c = 200;
    dbg(b = &c);

    return nullptr;
}

void* fun2(void*) {
    dbg(a);
    dbg(b);

    sleep(2);
    dbg("------2s------");

    dbg(a, *a);
    dbg(b, *b);
    return nullptr;
} 

int main() {
    pthread_t p1, p2;
    pthread_create(&p1, nullptr, fun1, nullptr);
    pthread_create(&p2, nullptr, fun2, nullptr);
    pthread_join(p2, nullptr);
}
提示:
推荐使用 <a href=“https://github.com/sharkdp/dbg-macro"target="_blank" rel=“external nofollow noopener noreferrer”>dbg-macro 方便地输出调试信息。

结果在 Ubuntu 18.0 中,测试结果如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[test.cpp:19 (fun2)] a = nullptr (int*)
[test.cpp:20 (fun2)] b = nullptr (int*)
[test.cpp:9 (fun1)] ------1s------
[test.cpp:11 (fun1)] a = new int(1000) = 0x7fa154000e10 (int*&)
[test.cpp:13 (fun1)] b = &c = 0x7fa162597e64 (int*&)
[test.cpp:23 (fun2)] ------2s------
[test.cpp:25 (fun2)] a = 0x7fa154000e10 (int*)
[test.cpp:25 (fun2)] *a = 1000 (int&)
[test.cpp:26 (fun2)] b = 0x7fa162597e64 (int*)
[test.cpp:26 (fun2)] *b = 200 (int&)

在 Mac OS X 中 测试结果如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[test.cpp:19 (fun2)] a = nullptr (int*)
[test.cpp:20 (fun2)] b = nullptr (int*)
[test.cpp:9 (fun1)] ------1s------
[test.cpp:11 (fun1)] a = new int(1000) = 0x7f81c4d040d0 (int*&)
[test.cpp:13 (fun1)] b = &c = 0x7000003f6e9c (int*&)
[test.cpp:23 (fun2)] ------2s------
[test.cpp:25 (fun2)] a = 0x7f81c4d040d0 (int*)
[test.cpp:25 (fun2)] *a = 1000 (int&)
[test.cpp:26 (fun2)] b = 0x7000003f6e9c (int*)
[1]    54143 segmentation fault  "/Users/lulu/Desktop/code/"test
结果:
说明在 Mac OS X 中,线程之间的栈不能相互访问,而在 Ubuntu 中,线程之间可以访问各自的栈变量。而两个系统环境下,不同线程下可以互相访问各自的 heap 变量。
0%