⏳ 线程生命周期
第3章 · 启动、运行、阻塞与结束 —— 掌控线程的每一帧
线程从被创建到终止,经历一系列明确的状态转换。理解这些状态是编写健壮多线程程序的基础,尤其在摄像头流水线中,线程的阻塞与唤醒直接影响帧率。
▲ 线程五大状态及转换关系(阻塞以琥珀色高亮)
1. 线程的启动
通过 threading.Thread(target=func) 创建线程对象后,线程处于新建状态。调用 start() 使其进入就绪队列,等待操作系统调度。
import threading
import time
def camera_task():
# 模拟摄像头初始化
time.sleep(0.1)
print("摄像头线程已启动")
cap_thread = threading.Thread(target=camera_task, name="CameraThread")
cap_thread.start() # 启动线程,进入就绪态
2. 运行与阻塞
线程获得 CPU 时间片后进入运行状态。当遇到 I/O 操作(如 cv2.VideoCapture.read() 等待帧)、time.sleep() 或请求锁时,线程主动阻塞,让出 CPU。阻塞结束后重新回到就绪队列。
▲ 摄像头读取线程在阻塞-就绪间切换,等待帧到达
3. 阻塞的常见原因
| 阻塞类型 | 典型场景 | 唤醒方式 |
|---|---|---|
| I/O 阻塞 | 摄像头 read()、网络请求 | 数据就绪 / 超时 |
| 锁阻塞 | acquire() 未获得锁 | 锁被释放 |
| 睡眠阻塞 | time.sleep() | 睡眠结束 |
| 条件变量 | wait() 等待事件 | notify() / notify_all() |
4. 线程的结束
线程函数自然返回或抛出异常时,线程进入终止状态。也可以使用 threading.Event 优雅通知线程退出,避免强制终止。
import threading
import time
stop_event = threading.Event()
def camera_loop():
while not stop_event.is_set():
# 模拟读取帧
time.sleep(0.03)
print("帧处理中...")
print("线程安全退出")
t = threading.Thread(target=camera_loop)
t.start()
time.sleep(0.2)
stop_event.set() # 通知线程结束
t.join() # 等待线程终止
▲ 使用 Event 实现协作式终止,避免 Thread.stop()
5. 生命周期在摄像头流水线中的意义
- 启动:为每一路摄像头创建独立线程,避免阻塞主循环。
- 阻塞:合理利用阻塞等待帧,降低 CPU 空转;但需注意死锁。
- 结束:使用
join()确保资源释放,防止僵尸线程。