Skip to content

进程管理

什么是进程?

进程(Process)是程序的一次执行过程,是系统进行资源分配和调度的基本单位。

进程 vs 程序 vs 线程

特性程序进程线程
定义静态的代码和数据程序的执行实例进程内的执行单元
资源-独立的资源共享进程资源
开销-
通信-IPC机制共享内存
切换-

进程状态

五状态模型

         创建

    ┌─→ 就绪 ←─┐
    │    ↓     │
  阻塞 ← 运行  │
    │         │
    └─────────┘

        终止
  1. 新建(New):进程正在创建
  2. 就绪(Ready):等待CPU调度
  3. 运行(Running):正在执行
  4. 阻塞(Blocked/Waiting):等待事件发生
  5. 终止(Terminated):执行完成

状态转换

  • 就绪 → 运行:调度程序选中
  • 运行 → 就绪:时间片用完
  • 运行 → 阻塞:等待I/O或事件
  • 阻塞 → 就绪:I/O完成或事件发生
  • 运行 → 终止:执行完成或异常

进程控制块(PCB)

PCB(Process Control Block)存储进程的所有信息。

PCB包含的信息

c
struct PCB {
    int pid;              // 进程ID
    int ppid;             // 父进程ID
    int state;            // 进程状态
    int priority;         // 优先级
    CPU_Context context;  // CPU上下文
    MemoryInfo memory;    // 内存信息
    FileTable files;      // 打开的文件
    ...
};

主要内容

  • 进程标识信息:PID、PPID、用户ID
  • 处理机状态信息:寄存器、PC、PSW
  • 进程调度信息:状态、优先级、调度参数
  • 进程控制信息:内存指针、文件描述符

进程创建和终止

Linux进程创建

c
#include <unistd.h>
#include <stdio.h>

int main() {
    pid_t pid = fork();  // 创建子进程
    
    if (pid < 0) {
        // fork失败
        printf("Fork failed!\n");
    } else if (pid == 0) {
        // 子进程
        printf("Child process: PID=%d\n", getpid());
    } else {
        // 父进程
        printf("Parent process: PID=%d, Child PID=%d\n", 
               getpid(), pid);
    }
    
    return 0;
}

exec系统调用

c
#include <unistd.h>

int main() {
    pid_t pid = fork();
    
    if (pid == 0) {
        // 子进程执行新程序
        execl("/bin/ls", "ls", "-l", NULL);
        // 如果exec成功,下面的代码不会执行
        printf("Exec failed!\n");
    }
    
    return 0;
}

进程终止

c
#include <stdlib.h>

// 正常终止
exit(0);      // 执行清理工作(刷新缓冲区等)
_exit(0);     // 立即终止

// 父进程等待子进程
#include <sys/wait.h>

int status;
pid_t child_pid = wait(&status);  // 等待任意子进程
// 或
pid_t child_pid = waitpid(pid, &status, 0);  // 等待指定子进程

进程调度

调度算法

1. 先来先服务(FCFS)

按进程到达顺序调度。

特点

  • 简单公平
  • 不可抢占
  • 平均等待时间长
进程  到达时间  运行时间
P1      0        10
P2      1        5
P3      2        8

执行顺序:P1 → P2 → P3

2. 短作业优先(SJF)

选择运行时间最短的进程。

特点

  • 平均等待时间最短
  • 可能饿死长进程
  • 需要预知运行时间

3. 优先级调度

按进程优先级调度。

特点

  • 灵活
  • 可能饿死低优先级进程
  • 需要动态调整优先级
c
// Linux nice值:-20(最高)到 19(最低)
nice -n 10 command  // 降低优先级
renice -n -5 -p PID // 提高优先级

4. 时间片轮转(RR)

每个进程分配固定时间片。

特点

  • 公平
  • 响应时间快
  • 时间片大小影响性能
时间片 = 10ms
进程队列:P1(30ms) → P2(20ms) → P3(15ms)

执行:
P1(10ms) → P2(10ms) → P3(10ms) →
P1(10ms) → P2(10ms) → P3(5ms) →
P1(10ms)

5. 多级反馈队列

结合多种调度算法。

高优先级队列(时间片=10ms)
    ↓ 未完成
中优先级队列(时间片=20ms)
    ↓ 未完成
低优先级队列(FCFS)

特点

  • 综合性能好
  • Linux和Windows采用

Linux调度器

CFS(Completely Fair Scheduler)

Linux使用的调度器,基于虚拟运行时间。

c
vruntime = 实际运行时间 * (NICE_0_LOAD / 进程权重)

特点

  • 公平调度
  • O(log n) 复杂度
  • 支持实时进程

进程通信(IPC)

1. 管道(Pipe)

半双工通信,只能在父子进程间使用。

c
#include <unistd.h>

int main() {
    int fd[2];
    pipe(fd);  // fd[0]读端,fd[1]写端
    
    pid_t pid = fork();
    
    if (pid == 0) {
        // 子进程:写数据
        close(fd[0]);
        write(fd[1], "Hello", 5);
        close(fd[1]);
    } else {
        // 父进程:读数据
        close(fd[1]);
        char buf[10];
        read(fd[0], buf, 5);
        close(fd[0]);
        printf("Received: %s\n", buf);
    }
    
    return 0;
}

2. 命名管道(FIFO)

可以在无关进程间通信。

c
#include <sys/types.h>
#include <sys/stat.h>

// 创建FIFO
mkfifo("/tmp/myfifo", 0666);

// 写进程
int fd = open("/tmp/myfifo", O_WRONLY);
write(fd, "Hello", 5);
close(fd);

// 读进程
int fd = open("/tmp/myfifo", O_RDONLY);
char buf[10];
read(fd, buf, 5);
close(fd);

3. 消息队列

消息队列是消息的链表。

c
#include <sys/msg.h>

// 创建消息队列
int msgid = msgget(IPC_PRIVATE, 0666);

// 发送消息
struct msgbuf {
    long mtype;
    char mtext[100];
};
struct msgbuf msg = {1, "Hello"};
msgsnd(msgid, &msg, sizeof(msg.mtext), 0);

// 接收消息
struct msgbuf rcv;
msgrcv(msgid, &rcv, sizeof(rcv.mtext), 1, 0);

// 删除消息队列
msgctl(msgid, IPC_RMID, NULL);

4. 共享内存

最快的IPC方式。

c
#include <sys/shm.h>

// 创建共享内存
int shmid = shmget(IPC_PRIVATE, 1024, 0666);

// 连接共享内存
char *ptr = (char*)shmat(shmid, NULL, 0);

// 写数据
strcpy(ptr, "Hello");

// 读数据
printf("%s\n", ptr);

// 断开连接
shmdt(ptr);

// 删除共享内存
shmctl(shmid, IPC_RMID, NULL);

5. 信号量

用于进程同步。

c
#include <sys/sem.h>

// 创建信号量
int semid = semget(IPC_PRIVATE, 1, 0666);

// 初始化信号量
semctl(semid, 0, SETVAL, 1);

// P操作(等待)
struct sembuf p = {0, -1, 0};
semop(semid, &p, 1);

// V操作(信号)
struct sembuf v = {0, 1, 0};
semop(semid, &v, 1);

// 删除信号量
semctl(semid, 0, IPC_RMID);

6. 套接字(Socket)

可以跨网络通信。

c
// 服务器
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
bind(sockfd, ...);
listen(sockfd, 5);
int connfd = accept(sockfd, ...);
read(connfd, buf, size);
write(connfd, buf, size);

// 客户端
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
connect(sockfd, ...);
write(sockfd, buf, size);
read(sockfd, buf, size);

线程

线程 vs 进程

进程:
┌─────────────────────┐
│     进程            │
│  ┌────┐  ┌────┐    │
│  │代码│  │数据│    │
│  └────┘  └────┘    │
│  ┌────┐  ┌────┐    │
│  │堆  │  │栈  │    │
│  └────┘  └────┘    │
└─────────────────────┘

多线程进程:
┌─────────────────────┐
│     进程            │
│  ┌────┐  ┌────┐    │
│  │代码│  │数据│    │ 共享
│  └────┘  └────┘    │
│  ┌────┐            │
│  │堆  │            │
│  └────┘            │
│  ┌────┬────┬────┐  │
│  │栈1 │栈2 │栈3 │  │ 独立
│  └────┴────┴────┘  │
└─────────────────────┘

POSIX线程

c
#include <pthread.h>

void* thread_func(void* arg) {
    printf("Thread ID: %ld\n", pthread_self());
    return NULL;
}

int main() {
    pthread_t tid;
    
    // 创建线程
    pthread_create(&tid, NULL, thread_func, NULL);
    
    // 等待线程结束
    pthread_join(tid, NULL);
    
    return 0;
}

线程同步

c
// 互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&mutex);
// 临界区
pthread_mutex_unlock(&mutex);

// 条件变量
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_cond_wait(&cond, &mutex);
pthread_cond_signal(&cond);

// 读写锁
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
pthread_rwlock_rdlock(&rwlock);  // 读锁
pthread_rwlock_wrlock(&rwlock);  // 写锁
pthread_rwlock_unlock(&rwlock);

死锁

死锁的四个必要条件

  1. 互斥:资源不能共享
  2. 持有并等待:持有资源并等待其他资源
  3. 不可抢占:不能强制剥夺资源
  4. 循环等待:存在循环等待链

死锁预防

破坏四个必要条件之一。

  • 破坏互斥:无法实现(有些资源本身互斥)
  • 破坏持有并等待:一次性分配所有资源
  • 破坏不可抢占:允许抢占资源
  • 破坏循环等待:资源有序分配

死锁避免

银行家算法:检查分配后是否处于安全状态。

死锁检测和恢复

  • 定期检测死锁
  • 发现后终止进程或抢占资源

💡 提示

这是一个demo文档,欢迎补充更多进程管理相关内容。

基于 VitePress 构建