--- tags: [笔试, 微派, 操作系统, 线程, 内存] create time: 2026-05-16 15:00 --- # 06 - 单选题 4:线程的资源隔离 ## 题目 在同一进程中创建的多个线程之间,以下哪一项资源是**不共享**的? | 选项 | 内容 | |------|------| | A | 堆(Heap)内存 | | B | 文件描述符表 | | C | 栈(Stack)空间 | | D | 信号处理函数 |
点击查看答案与解析 ### ✅ 正确答案:**C** --- ### 详细解析 #### 进程 vs 线程的资源划分 ```mermaid graph TD %%{init: {'theme':'base','themeVariables': {'tertiaryColor':'#f0f4f8'}}}%% P["🏢 进程地址空间"] subgraph SH ["▸ 所有线程共享"] HEAP["📦 堆 Heap"] DATA["📄 数据段
全局/静态变量"] BSS["📜 BSS 段
未初始化全局变量"] CODE["🔧 代码段 .text"] FD["📋 文件描述符表"] SIG["⚙️ 信号处理函数"] CWD["🏠 当前工作目录"] end subgraph PT ["▸ 每个线程独有"] ST1["📚 栈 Stack"] REG["🎛️ 寄存器集合"] PC["💻 程序计数器 PC"] TLS["🔒 线程本地存储 TLS"] ERRNO["🚩 错误号 errno"] end SEP["━━━━━━━━ 分 隔 ━━━━━━━━"] ALL[". . . 所有线程可见 . . ."] T1["线程 1"] T2["线程 2"] T3["线程 3"] SH --> ALL PT --> T1 PT --> T2 PT --> T3 style SH fill:#e8f5e9,stroke:#4caf50,color:#1b5e20 style PT fill:#fff3e0,stroke:#ff9800,color:#e65100 style SEP stroke-dasharray: 5 5,fill:#fafafa,stroke:#bbb style ALL stroke:none,fill:none,color:#999 style T1,T2,T3 stroke:none,fill:none,color:#999 ``` #### 逐项分析 | 选项 | 正误 | 原因 | |------|------|------| | A | ❌ 不选 | **堆是共享的**。所有线程通过相同的堆指针访问堆内存,所以动态分配的内存对所有线程可见。这也是为什么多线程并发访问同一堆对象需要加锁 | | B | ❌ 不选 | **文件描述符表是共享的**。`open()` 返回的文件描述符对所有线程有效,一个线程打开的文件可以在另一个线程中关闭 | | C | ✅ **正确** | **每个线程有自己独立的栈空间!** 每个线程调用函数时的局部变量、返回地址、函数参数都在自己的栈上。**互不干扰** | | D | ❌ 不选 | **信号处理函数是共享的**。注册了一个信号处理器后,该进程的所有线程都会响应这个处理逻辑 | #### 为什么每线程独立栈? 这是设计上的必然选择: 1. **函数调用需要局部变量隔离**: `foo()` 在线程 1 中的 `x = 42` 不应该影响线程 2 中的 `x` 2. **返回地址独立**: 每个线程调用同一个函数,返回地址各自不同 3. **防止栈溢出牵连其他线程**: 如果一个线程的栈爆了,不会影响其他线程的执行 #### 对比:进程 vs 线程 | 资源 | 进程间 | 线程间 | |------|--------|--------| | 地址空间 | ❌ 独立 | ✅ 共享 | | 堆 | ❌ 独立 | ✅ 共享 | | 栈 | ❌ 独立 | ❌ 独立(每线程一块) | | 文件描述符 | ❌ 独立(可inherit via fork) | ✅ 共享 | | 通信成本 | 高 (IPC) | 低(直接读写共享内存) | > [!tip] Go 语言的 goroutine 区别 > Goroutine 和线程类似——每个 goroutine 有自己的栈。但 Go 使用**可增长的栈**(初始仅 2KB),且调度器从用户态出发,比系统级线程更轻量。