Skip to content

Latest commit

 

History

History
196 lines (142 loc) · 5.46 KB

File metadata and controls

196 lines (142 loc) · 5.46 KB

1.1 进程管理

📍 导航返回目录 | 下一节:内存管理


核心原理

进程与线程

  • 进程(Process):系统资源分配的基本单位,拥有独立的地址空间、文件描述符、进程 ID 等资源
  • 线程(Thread):CPU 调度的基本单位,同一进程内的线程共享地址空间和资源
  • 轻量级进程(LWP):Linux 通过 clone() 系统调用实现线程,本质是共享资源的进程

进程状态转换

创建 → 就绪(R) ⇄ 运行(R) → 终止(Z)
         ↓  ↑
    阻塞/睡眠(S/D)

状态说明

  • R (Running/Runnable):运行或就绪状态
  • S (Interruptible Sleep):可中断睡眠,等待资源或事件
  • D (Uninterruptible Sleep):不可中断睡眠,通常等待 IO
  • Z (Zombie):僵尸状态,进程已终止但父进程未回收
  • T (Stopped):暂停状态

进程调度

Linux 采用 CFS(完全公平调度器,Completely Fair Scheduler)

  • 基于虚拟运行时间(vruntime)调度
  • 红黑树维护就绪队列
  • 时间片动态分配,保证每个进程的公平性
  • 支持优先级(nice 值:-20 到 19,数值越小优先级越高)

关键命令与工具

# 查看进程信息
ps aux                    # 查看所有进程
ps -eLf                   # 查看所有线程
top                       # 实时监控进程
htop                      # 增强版 top

# 进程控制
kill -SIGTERM <pid>       # 优雅终止进程(15信号)
kill -SIGKILL <pid>       # 强制杀死进程(9信号)
nice -n 10 ./app          # 以指定优先级启动
renice -n 5 -p <pid>      # 调整运行中进程优先级

# 进程追踪
strace -p <pid>           # 追踪系统调用
pstack <pid>              # 查看进程调用栈
lsof -p <pid>             # 查看进程打开的文件

# CPU 亲和性
taskset -c 0,1 ./app      # 将进程绑定到指定 CPU 核心

实战示例:进程池模型(Python3)

完整代码见:examples/python/process-pool/

import multiprocessing as mp
import time
from typing import Callable

class ProcessPool:
    """简单的进程池实现"""
    
    def __init__(self, num_workers: int = 4):
        self.num_workers = num_workers
        self.task_queue = mp.Queue()
        self.result_queue = mp.Queue()
        self.workers = []
        
    def worker(self):
        """工作进程主循环"""
        while True:
            task = self.task_queue.get()
            if task is None:  # 毒丸,退出信号
                break
            func, args = task
            try:
                result = func(*args)
                self.result_queue.put(('success', result))
            except Exception as e:
                self.result_queue.put(('error', str(e)))
    
    def start(self):
        """启动工作进程"""
        for _ in range(self.num_workers):
            p = mp.Process(target=self.worker)
            p.start()
            self.workers.append(p)
    
    def submit(self, func: Callable, *args):
        """提交任务"""
        self.task_queue.put((func, args))
    
    def shutdown(self):
        """关闭进程池"""
        for _ in range(self.num_workers):
            self.task_queue.put(None)  # 发送退出信号
        for p in self.workers:
            p.join()

# 使用示例
def cpu_intensive_task(n):
    """CPU 密集型任务示例"""
    return sum(i * i for i in range(n))

if __name__ == '__main__':
    pool = ProcessPool(num_workers=4)
    pool.start()
    
    # 提交任务
    for i in range(10):
        pool.submit(cpu_intensive_task, 1000000)
    
    # 获取结果
    for _ in range(10):
        status, result = pool.result_queue.get()
        print(f"Task result: {status}, {result}")
    
    pool.shutdown()

常见问题与优化

僵尸进程问题

原因:子进程退出后,父进程未调用 wait()/waitpid() 回收

危害:占用进程表项,系统进程数达到上限

解决方案

import signal

# 设置 SIGCHLD 信号处理器自动回收
signal.signal(signal.SIGCHLD, signal.SIG_IGN)

进程上下文切换优化

  • 减少不必要的系统调用
  • 使用 CPU 亲和性绑定核心
  • 合理设置进程优先级
  • 避免频繁的阻塞操作

孤儿进程

  • 父进程先于子进程退出,子进程被 init 进程(PID 1)接管
  • 通常不会造成问题,init 会自动回收

本章小结

进程管理是操作系统的核心功能,理解进程状态转换、调度算法对于编写高性能后台服务至关重要。

关键要点

  • ✅ 进程 vs 线程:资源分配 vs CPU调度
  • ✅ CFS调度器:公平性保证
  • ✅ 避免僵尸进程:正确处理SIGCHLD信号
  • ✅ 进程池模式:复用进程,减少创建开销

扩展阅读


💡 思考题

  1. 进程和线程的本质区别是什么?什么时候用进程,什么时候用线程?
  2. 如何排查和清理僵尸进程?
  3. CPU密集型任务应该用多进程还是多线程?为什么?

⏭️ 下一节:内存管理