漂亮!你刚问了 进程 fork 的虚拟地址问题,现在追问 线程的虚拟地址空间——这就是操作系统理解的进阶节奏了!
✅ 简明回答:
线程之间共享同一个虚拟地址空间。
也就是说:
- 多个线程属于同一个进程;
- 它们共享进程的代码段、堆、数据段、文件描述符等资源;
- 唯一“私有”的是每个线程的 栈(stack) 和部分寄存器(如 esp/ebp)。
🧠 为什么线程地址空间要共享?
线程是“轻量级进程”,本质上是执行路径,它不需要额外的虚拟内存空间,只是进程空间内的另一个执行流。
一个进程 fork 出来是“复制一个世界”,
一个线程创建出来是“多一个人用这个世界”。
👥 对比:进程 vs 线程的虚拟内存
项目 | 进程(fork) | 线程(pthread_create) |
---|---|---|
虚拟地址空间 | 独立 | 共享 |
物理内存 | 初始共享(COW),后独立 | 完全共享 |
页表 | 各自独立 | 共享同一套 |
数据段 / 堆 | 各自独立 | 共享 |
文件描述符表 | 拷贝一份 | 共享 |
栈 | 独立(新内核栈 + 用户栈) | 独立(每个线程自己的栈) |
切换开销 | 高(切换页表、TLB刷新) | 低(仅保存寄存器和栈) |
🧪 实验演示
你可以用以下代码验证线程共享地址空间:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
int global = 100;
void *thread_func(void *arg) {
printf("Thread: global address = %p, value = %d\n", &global, global);
global = 200;
return NULL;
}
int main() {
pthread_t tid;
printf("Main: global address = %p, value = %d\n", &global, global);
pthread_create(&tid, NULL, thread_func, NULL);
pthread_join(tid, NULL);
printf("Main after thread: global = %d\n", global);
return 0;
}
输出:
Main: global address = 0x... , value = 100
Thread: global address = 0x... , value = 100
Main after thread: global = 200
👉 地址一样,值也被线程改了,说明它们确实共享同一个虚拟地址空间!
✅ 一句话总结(面试回答)
线程属于同一进程,多个线程共享相同的虚拟地址空间(代码段、数据段、堆等),只有栈是独立的,这样线程之间可以轻松共享数据,适合并发模型。