进程管理
什么是进程?
进程(Process)是程序的一次执行过程,是系统进行资源分配和调度的基本单位。
进程 vs 程序 vs 线程
| 特性 | 程序 | 进程 | 线程 |
|---|---|---|---|
| 定义 | 静态的代码和数据 | 程序的执行实例 | 进程内的执行单元 |
| 资源 | - | 独立的资源 | 共享进程资源 |
| 开销 | - | 大 | 小 |
| 通信 | - | IPC机制 | 共享内存 |
| 切换 | - | 慢 | 快 |
进程状态
五状态模型
创建
↓
┌─→ 就绪 ←─┐
│ ↓ │
阻塞 ← 运行 │
│ │
└─────────┘
↓
终止- 新建(New):进程正在创建
- 就绪(Ready):等待CPU调度
- 运行(Running):正在执行
- 阻塞(Blocked/Waiting):等待事件发生
- 终止(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 → P32. 短作业优先(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);死锁
死锁的四个必要条件
- 互斥:资源不能共享
- 持有并等待:持有资源并等待其他资源
- 不可抢占:不能强制剥夺资源
- 循环等待:存在循环等待链
死锁预防
破坏四个必要条件之一。
- 破坏互斥:无法实现(有些资源本身互斥)
- 破坏持有并等待:一次性分配所有资源
- 破坏不可抢占:允许抢占资源
- 破坏循环等待:资源有序分配
死锁避免
银行家算法:检查分配后是否处于安全状态。
死锁检测和恢复
- 定期检测死锁
- 发现后终止进程或抢占资源
💡 提示
这是一个demo文档,欢迎补充更多进程管理相关内容。