进程相关知识day1
一、进程的基本概念
-
进程的定义
- 进程是正在执行的程序,是资源分配和调度的独立单元。
- 例如:QQ的多个聊天窗口、一个程序中多个死循环同时执行。
-
程序与进程的区别
- 程序:静态的二进制文件,存储在硬盘。
- 进程:动态的程序运行过程,存在于内存,包含创建、调度、终止等阶段。
二、进程的调度机制
- CPU时间片轮询:CPU以毫秒级速度在多个进程/线程间切换,实现“并发”执行。
三、进程的五态图
- 创建态:申请PCB(进程控制块),填写信息,分配资源后进入就绪队列。
- 就绪态:已获取除CPU外的所有资源,等待CPU调度。
- 运行态:获取CPU资源,执行指令。
- 阻塞态:因等待I/O操作或事件而暂停。
- 终止态:释放资源,回收PCB。
四、虚拟内存与物理内存
- 物理内存:真实内存条上的存储空间。
- 虚拟内存:
- 进程创建时分配4GB虚拟内存(用户空间0-3G独立,内核空间3-4G共享)。
- 虚拟内存通过映射管理物理内存,解决物理内存不足问题。
- 32位系统虚拟内存为4GB,64位系统一般为256TB(48位地址)。
五、进程标识
- PID:进程唯一标识符(如
pidof a.out
查看进程号)。 - PPID:父进程ID。
- PGID:进程组ID,默认继承父进程。
- SID:会话ID,默认继承父进程。
六、特殊进程
- 0号进程(
PID=0
):系统引导进程(idel)。 - 1号进程(
PID=1
):init进程,回收孤儿进程。 - 2号进程(
PID=2
):kthread进程,负责调度。
七、进程相关Shell指令
指令 | 用途 |
---|---|
ps -ef | 查看所有进程信息 |
ps -aux | 查看内存使用情况 |
ps -ajx | 查看进程树 |
kill -9 PID | 强制终止进程(SIGKILL信号) |
kill -l | 查看所有信号(共62种) |
八、进程状态(man ps
查看)
- R:运行/就绪
- S:可中断休眠(如等待输入)
- Z:僵尸进程(已终止但未被回收)
- D:不可中断休眠(通常为I/O)
- T:被作业控制信号停止(如
Ctrl+Z
挂起)
九、关键进程函数
-
fork()
- 功能:创建子进程,父子进程独立执行。
- 特点:
- 调用一次,返回两次(父进程返回子进程PID,子进程返回0)。
- 子进程复制父进程的用户空间和文件描述符表。
-
exit()
与_exit()
exit()
:库函数,刷新缓冲区后再终止进程。_exit()
:系统调用,直接终止进程,不刷新缓冲区。
-
wait()/waitpid()
- 功能:阻塞回收子进程资源,防止僵尸进程。
waitpid
支持非阻塞模式(WNOHANG
选项)。
十、特殊进程处理
-
僵尸进程
- 成因:子进程终止,父进程未回收资源(
wait
未调用)。 - 危害:占用系统资源。
- 解决:通过
wait
回收或终止父进程(由系统回收)。
- 成因:子进程终止,父进程未回收资源(
-
孤儿进程
- 成因:父进程终止,子进程被1号进程(init)收养。
- 特点:无害,可被
kill
终止。
十一、作业示例
- 父子进程协作拷贝文件:
- 父进程拷贝前半部分,子进程拷贝后半部分。
- 使用diff查看两个文件是否相同
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include<stdio.h>
#define BUF_SIZE 4096 // 定义缓冲区大小为4KB
int main()
{
// 定义文件路径
const char *src = "xiaoxin.bmp"; // 源文件路径
const char *dst = "copy_xiaoxin.bmp"; // 目标文件路径
struct stat st; // 文件状态结构体
int fd_src, fd_dst; // 文件描述符
/************************** 获取源文件大小 **************************/
fd_src = open(src, O_RDONLY); // 只读方式打开源文件
if (fd_src < 0)
{
perror("打开源文件失败");
return -1;
}
fstat(fd_src, &st); // 获取文件状态信息
off_t size = st.st_size; // 文件总大小
off_t half = size / 2; // 计算半文件大小
close(fd_src); // 先关闭源文件
/************************** 创建目标文件 **************************/
// 创建并清空目标文件(权限rw-rw-rw-)
fd_dst = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd_dst < 0)
{
perror("创建目标文件失败");
return -1;
}
ftruncate(fd_dst, size); // 预分配目标文件空间
close(fd_dst); // 关闭目标文件
/************************** 创建子进程 **************************/
pid_t pid = fork(); // 创建子进程
if (pid > 0)
{ // 父进程分支
/******************** 父进程:拷贝前半部分 ********************/
char buf[BUF_SIZE]; // 数据缓冲区
// 重新打开源文件
if ((fd_src = open(src, O_RDONLY)) < 0)
{
perror("父进程打开源文件失败");
return -1;
}
// 以写方式打开目标文件
if ((fd_dst = open(dst, O_WRONLY)) < 0)
{
perror("父进程打开目标文件失败");
close(fd_src);
return -1;
}
// 定位到文件起始位置
lseek(fd_src, 0, SEEK_SET);
lseek(fd_dst, 0, SEEK_SET);
// 分块拷贝前半部分
printf("父进程开始拷贝前数据...\n");
for (off_t copied = 0; copied < half;)
{
ssize_t n = read(fd_src, buf, BUF_SIZE); // 读取数据块
if (n <= 0) break;
if (write(fd_dst, buf, n) != n)
{ // 写入数据块
perror("父进程写入失败");
close(fd_src);
close(fd_dst);
return -1;
}
copied += n;
}
close(fd_src);
close(fd_dst);
wait(NULL); // 等待子进程完成
printf("================= 文件校验 =================\n");
// 执行diff命令校验文件
int ret = system("diff xiaoxin.bmp copy_xiaoxin.bmp");
if (ret == 0) {
printf("校验结果:文件完全一致!\n");
} else {
printf("警告:文件内容存在差异!\n");
}
}
else if (pid == 0) { // 子进程分支
/******************** 子进程:拷贝后半部分 ********************/
char buf[BUF_SIZE];
// 重新打开源文件
if ((fd_src = open(src, O_RDONLY)) < 0)
{
perror("子进程打开源文件失败");
_exit(-1);
}
// 以写方式打开目标文件
if ((fd_dst = open(dst, O_WRONLY)) < 0)
{
perror("子进程打开目标文件失败");
close(fd_src);
_exit(-1);
}
// 定位到文件中间位置
lseek(fd_src, half, SEEK_SET);
lseek(fd_dst, half, SEEK_SET);
// 分块拷贝后半部分
printf("子进程开始拷贝后数据...\n");
for (off_t copied = 0; copied < size - half;)
{
ssize_t n = read(fd_src, buf, BUF_SIZE);
if (n <= 0) break;
if (write(fd_dst, buf, n) != n)
{
perror("子进程写入失败");
close(fd_src);
close(fd_dst);
_exit(-1);
}
copied += n;
}
close(fd_src);
close(fd_dst);
_exit(0); // 子进程直接退出
}
return 0;
}