进程与线程
进程是带资源与地址空间上下文的运行程序。进程内线程共享内存,但有独立执行状态与栈。不同进程通常隔离普通内存,通信需管道、套接字或共享设施。进程可就绪、运行或因 I/O 阻塞。程序文件静态,同一文件可由多个进程执行。线程并发不代表 CPU 同时执行,解释器限制不同于系统保证。
同进程两线程共享全部栈帧吗?
完整解答
不,栈独立,但可访问共享对象。
调度与上下文切换
调度器选择就绪工作。先来先服务简单,但长任务阻挡短任务。时间片轮转改善交互响应,片过小增加切换开销。周转为完成减到达,响应为首次服务减到达。保存恢复寄存器让切换后继续。公平、吞吐与延迟是不同目标,评估策略需负载与目标。
响应时间等于周转时间吗?
完整解答
不,任务可很早开始却很晚完成。
虚拟内存与分页
虚拟地址通过页映射转换到物理存储,页号选映射、偏移选页内字节。4096 字节页中地址 8197 为页二、偏移五。权限与独立映射隔离进程,TLB 缓存转换。缺页把控制交给系统,可分配、加载或拒绝,并非总读磁盘。虚拟内存是地址空间抽象,而非仅用磁盘增加 RAM。
1024 字节页中,2051 如何拆分?
完整解答
页二、偏移三。
文件、句柄与持久化
文件提供有名字的持久数据,句柄跟踪打开实例与位置。用上下文管理器在异常后也可靠关闭。目录组织名字,权限管理操作。缓冲意味着写调用成功不一定已物理持久。抗崩溃更新需明确持久与原子策略。临时目录实验展示生命周期,而非持久数据库事务。
写入缓冲保证断电后仍在吗?
完整解答
不保证,持久性需额外保证。
竞态、锁与死锁
读改写可交错:双方读零、都写一,一次递增丢失。需同一锁保护整个临界区,而非仅最终写。常规 Python 的 GIL 不是应用事务保证。线程持有资源并循环等待其他资源可死锁,统一锁顺序有助避免。屏障实验强制特定顺序,无需依赖睡眠或随机机会。
为何只锁赋值不足?
完整解答
陈旧读取可能已在锁外发生。
常见误解
- 并发可以不同时执行。
- 缺页未必是错误或磁盘操作。
实验准备
下载脚本,在终端中使用 Python 3.11 或更新版本运行:python m10_process.py. Windows 也可使用 py -3;部分系统使用 python3。实验仅用标准库。先预测结果,再运行并完成变体。不要使用 -O,以保留断言。下方输出由构建器实际运行捕获,两种语言使用相同代码与输出。
实验 1 — 进程与作用域文件
检查子进程 ID 不同,输出不嵌入机器相关 ID。
"""Observe an isolated child process and scoped file cleanup."""
import json, os, subprocess, sys, tempfile
from pathlib import Path
child = subprocess.run([sys.executable, "-c", "import os,json; print(json.dumps({'pid':os.getpid(),'answer':6*7}))"],
check=True, capture_output=True, text=True, timeout=10)
data = json.loads(child.stdout)
assert data["pid"] != os.getpid() and data["answer"] == 42
print("child is a different process:", data["pid"] != os.getpid())
print("child result:", data["answer"])
with tempfile.TemporaryDirectory() as folder:
path = Path(folder) / "catalogue.txt"
path.write_text("Dune\nFoundation\n", encoding="utf-8")
print("file records:", path.read_text(encoding="utf-8").splitlines())
print("temporary directory removed:", not Path(folder).exists())
child is a different process: True
child result: 42
file records: ['Dune', 'Foundation']
temporary directory removed: True
- 让子进程非零退出。
- 在调用者捕获 CalledProcessError。
- 解释临时路径为何消失。
完整解答
check=True 把非零退出转为 CalledProcessError,可查 returncode。临时目录上下文结束会清理自身内容,异常退出也如此。
实验 2 — 强制并修复竞态
屏障确保双方写前都已读旧值,安全版本锁住完整更新。
"""Force a lost update deterministically, then protect a critical section."""
from threading import Barrier, Lock, Thread
counter, barrier = [0], Barrier(2)
def unsafe():
old = counter[0]
barrier.wait(timeout=5) # both have read zero before either writes
counter[0] = old + 1
threads = [Thread(target=unsafe) for _ in range(2)]
for t in threads: t.start()
for t in threads: t.join(timeout=10); assert not t.is_alive()
print("forced lost update:", counter[0])
assert counter[0] == 1
counter[0] = 0
lock = Lock()
def safe():
for _ in range(1000):
with lock:
counter[0] = counter[0] + 1
threads = [Thread(target=safe) for _ in range(2)]
for t in threads: t.start()
for t in threads: t.join(timeout=10); assert not t.is_alive()
print("protected updates:", counter[0])
assert counter[0] == 2000
forced lost update: 1
protected updates: 2000
- 画强制交错。
- 把读取移到锁外,解释错误。
- 解释屏障放进互斥锁为何阻碍推进。
完整解答
A 读零、B 读零,双方写一。锁外读取可陈旧。若持锁者等双人屏障,另一人无法取锁到达,超时暴露死锁模式。
练习与完整解答
先尝试,再展开解答。★ 应用概念;★★ 结合概念;★★★ 进行设计或证明。
一个文件可有两个运行进程吗?
完整解答
可以,每次启动有独立状态与资源。
4096 字节页拆分 4100。
完整解答
页一,偏移四。
任务八与一同时到达,比较先 A 与先 B 平均周转。
完整解答
先 A 完成八九,平均 8.5;先 B 一九,平均五。工作相同,顺序影响均值。
双方读五并写旧值加一,结果?
完整解答
六而非七。
共享字典与线程局部循环索引哪个需协调?
完整解答
共享可变字典不变式需协调,独立局部索引本身不造成共享竞态。
两线程需 X、Y 锁,给一致获取规则。
完整解答
都先 X 后 Y,反序释放,移除两锁相反获取的循环等待。
两调用者借最后一本,什么需原子?
完整解答
库存检查、扣减与借阅创建需统一事务,仅锁扣减不能避免双方先通过检查。
解析异常为何仍需关文件?
完整解答
可靠释放资源,with 在正常与异常退出时都清理。
自测
选择答案查看反馈,重置后可重做。无需 JavaScript 也可阅读答案表。
同进程线程共享什么?
轮转选择什么?
缺页总是读盘吗?
锁应覆盖什么?
GIL 保证应用事务吗?
一致锁顺序有助避免什么?
答案表
- A — 栈独立。
- B — 轮换就绪工作。
- C — 还可分配或拒绝访问。
- A — 锁外陈旧读取仍危险。
- B — 仍需明确协调。
- C — 针对死锁条件。
引导阅读
复习与下一步
解释屏障如何产生丢失更新,再说明锁保护的不变式。模块 11 将通过协议连接进程。
关键术语
| 术语 | 含义 |
|---|---|
| 上下文切换 | 保存恢复执行状态以切换运行工作。 |
| 临界区 | 需协调访问共享状态的操作。 |
| 虚拟地址 | 通过进程映射上下文解释的地址。 |