前言
今天是7月3日,补昨天进程的内容。
概述
1.基础
2.代码演示
3.练习
1.基础
一、进程五态图
-
状态转换流程
创建态 → 就绪态 → 运行态 → 终止态 ↖______↙ 阻塞态
-
触发条件:
-
就绪态 → 运行态:获取CPU资源
-
运行态 → 阻塞态:等待I/O或资源
-
阻塞态 → 就绪态:资源就绪
-
-
-
进程ID关系
-
层级结构 :
SID (Session ID) > PGID (Group ID) > PPID (Parent PID) > PID
-
父子进程流:进程间形成树状依赖关系。
-
特殊ID:
-
0
:引导进程 -
1
:init进程(接收孤儿进程) -
2
:内核进程
-
-
二、进程查看指令
| 指令 | 功能描述 |
|------------------|-----------------|-------------|
| `ps -qix | grep a.out` | 查看特定进程的详细信息 |
| ps -qyx
| 显示所有进程(含线程) |
| pstree -p PPID
| 以树状图显示PPID下的进程树 |
| pidof a.out
| 获取进程的PID |
| kill -q PID
| 结束指定PID的进程 |
注意事项:
-
查看进程时需保持权限限制。
-
使用
pstree
可直观分析进程层级关系。
三、进程操作函数
-
创建进程
pid_t fork(void);
-
返回值:
-
父进程返回子进程PID
-
子进程返回0
-
-
特点:子进程复制父进程的地址空间。
-
-
退出进程
void exit(int status);
-
状态码:
-
EXIT_SUCCESS
(0):正常退出 -
EXIT_FAILURE
(非0):异常退出
-
-
-
获取进程ID
pid_t getpid(void); // 当前进程PID
pid_t getppid(void); // 父进程PID
-
回收子进程
pid_t wait(int *wstatus);
pid_t waitpid(pid_t pid, int *wstatus, int options);
- 功能:阻塞父进程,直到子进程退出。
四、关键概念补充
-
进程地址空间
fork()
后子进程继承父进程的地址空间副本,通过写时复制(Copy-On-Write)优化。
-
阻塞与非阻塞
-
阻塞调用 :如
wait()
,进程暂停直至条件满足。 -
非阻塞:需结合轮询或信号机制。
-
-
孤儿进程
- 父进程先终止时,子进程由init进程(PID=1)接管。
五、思维导图与笔记


2.代码演示
2.1 增:fork
cpp
#include <IO_head.h>
int main(int argc, const char* argv[]){
pid_t pid = fork();
printf("pid = %d\n", pid);
if(pid==0){
printf("son\n");
}
if(pid>0){
//sleep(1);
printf("father\n");
}
if(pid==-1){
ERROR("fork failed");
}
return 0;
}
bash
ubuntu@ubuntu:~/IO/class3$ ./01_fork
pid = 25767
father
pid = 0
son
2.2 删:exit
cpp
#include <IO_head.h>
int main(int argc, const char* argv[]){
//main函数也是进程,此处main作为父进程
pid_t pid = fork(); //创建子进程
//子进程:由fork函数返回
if(pid>0){
printf("pid = %d, ppid = %d, _%d_\n",getpid(),getppid(),__LINE__);
//getpid,getppid获取执行该语句的进程的pid,ppid
while(1){
//由于父进程占用了cpu资源,所以会打印
printf("father process\n");
sleep(1);
}
}
else if(pid==0){
printf("pid = %d, ppid = %d, _%d_\n",getpid(),getppid(),__LINE__);
exit(0);
//fflush(stdout);
//_exit
while(1){
//没资源,不打印
printf("son process\n");
sleep(1);
}
}
else{ERROR("");}
while(1);
return 0;
}
bash
ubuntu@ubuntu:~/IO/class3$ ./02_exit
pid = 25817, ppid = 23303, _7_
father process
pid = 25818, ppid = 25817, _16_
father process
father process
father process
father process
father process
^C
2.3 回收
cpp
#include <IO_head.h>
int main(int argc, const char* argv[]){
pid_t pid = fork();
if(pid>0){
//用status接收waitpid返回的子进程的退出值
int status;
waitpid(-1,&status,0); //注意wait和waitpid会阻塞函数
printf("father process\n");
//printf("status = %d\n",(status&0xff)>>8);
printf("status = %d\n",WEXITSTATUS(status));
}
else if(pid==0){
exit(EXIT_FAILURE);
//exit(EXIT_SUCCESS);
//exit(3);
//0:EXIT_SUCCESS;非0:EXIT_FAILURE
}
else{ERROR("");}
while(1);
return 0;
}
bash
ubuntu@ubuntu:~/IO/class3$ ./03_wait
father process
status = 3
^C
2.4 僵尸进程
cpp
#include <IO_head.h>
//若不回收子进程的资源,则成为僵尸进程
int main(int argc,const char* argv[]){
pid_t pid = fork();
if(pid>0){
while(1){
printf("father process\n");
sleep(1);
}
}else if(pid==0){
printf("son process\n");
exit(0);
}
else{ERROR("");}
return 0;
}
bash
ubuntu@ubuntu:~/IO/class4$ ./02_zombie
ubuntu@ubuntu:~/IO/class4$ ps -ajx | grep 02_zombie
3203 8410 8410 3203 pts/1 8410 S+ 1000 0:00 ./02_zombie
8410 8411 8410 3203 pts/1 8410 Z+ 1000 0:00 [02_zombie] <defunct>
8360 8474 8473 8360 pts/2 8473 S+ 1000 0:00 grep --color=auto 02_zombie
ubuntu@ubuntu:~/IO/class4$
2.5 守护进程
cpp
#include <IO_head.h>
//1.创建孤儿进程
int main(int argc,const char* argv[]){
pid_t pid = fork();
if(pid==0){
//2.设置新会话
setsid();
//3.把路径修改为根目录
chdir("/tmp");
//4写入
umask(0);
int guard_file_des = open("/tmp/my.txt", O_RDWR|O_APPEND|O_CREAT, 0777);
//4.2重新定向三个自带流指针
dup2(guard_file_des,0);
dup2(guard_file_des,1);
dup2(guard_file_des,2);
//4.1关闭3-1024576
for(int i = 3; i<getdtablesize(); ++i){
close(i);
}
while(1){
printf("son process\n");//写入
fflush(stdout); //刷新缓冲区
sleep(1);
}
}
else if(pid==-1){ERROR("");}
else if(pid>0){exit(0);}
return 0;
}
3.练习
补充:流程图

3.1扇形进程
cpp
#include <IO_head.h>
int main(int argc, const char* argv[]){
for(int i=0; i<=3; ++i){
pid_t pid = fork();
if(pid == -1){
ERROR("");
}else if(pid==0){ //son
printf("son process with id:%d\n",getpid());
break; //防止子进程继续繁殖
}else if(pid>0){ //father
NULL;
}
}
while(1);
return 0;
}
bash
ubuntu@ubuntu:~/IO/class3$ ps -ajx|grep h1_fan
23303 23659 23659 23303 pts/3 23659 R+ 1000 0:41 ./h1_fan
23659 23660 23659 23303 pts/3 23659 R+ 1000 0:41 ./h1_fan
23659 23661 23659 23303 pts/3 23659 R+ 1000 0:41 ./h1_fan
23659 23662 23659 23303 pts/3 23659 R+ 1000 0:41 ./h1_fan
23659 23663 23659 23303 pts/3 23659 R+ 1000 0:41 ./h1_fan
23607 23840 23839 23607 pts/1 23839 S+ 1000 0:00 grep --color=auto h1_fan
ubuntu@ubuntu:~/IO/class3$ pstree -p 23659
h1_fan(23659)─┬─h1_fan(23660)
├─h1_fan(23661)
├─h1_fan(23662)
└─h1_fan(23663)
3.2 链进程
cpp
#include <IO_head.h>
int main(int argc, const char* argv[]){
pid_t pid;
for(int i=0; i<=3; ++i){
pid = fork();
if(pid==-1){
ERROR("");
}else if(pid==0){ //son
printf("son process with id:%d\n",getpid());
NULL; //接着循环就行。
//把父进程阻塞了,子进程自然成了父进程,继续繁殖
}else if(pid>0){ //father
wait(NULL); //不能闭掉,因为闭掉子就也没了
//进入阻塞态是正确的。
exit(0); //跳出阻塞说明循环完了,回收一下资源
}
}
while(1);
return 0;
}
bash
ubuntu@ubuntu:~/IO/class3$ ps -ajx|grep h2_lincked
23303 24172 24172 23303 pts/3 24172 S+ 1000 0:00 ./h2_lincked
24172 24173 24172 23303 pts/3 24172 S+ 1000 0:00 ./h2_lincked
24173 24174 24172 23303 pts/3 24172 S+ 1000 0:00 ./h2_lincked
24174 24175 24172 23303 pts/3 24172 S+ 1000 0:00 ./h2_lincked
24175 24176 24172 23303 pts/3 24172 R+ 1000 0:22 ./h2_lincked
23607 24292 24291 23607 pts/1 24291 S+ 1000 0:00 grep --color=auto h2_lincked
ubuntu@ubuntu:~/IO/class3$ pstree -p 24172
h2_lincked(24172)───h2_lincked(24173)───h2_lincked(24174)───h2_lincked(24175)─+++
ubuntu@ubuntu:~/IO/class3$ pstree -p 23303
bash(23303)───h2_lincked(24172)───h2_lincked(24173)───h2_lincked(24174)───h2_lincked(24175)───h2+
3.3 分进程拷贝文件
cpp
#include <IO_head.h>
void RD_WR(int start, int end, int ori_des, int new_des){
lseek(ori_des, start, SEEK_SET);
lseek(new_des, start, SEEK_SET);
char buf;
for(int i = start; i<end;++i){
read(ori_des, &buf, 1);
write(new_des, &buf, 1);
}
printf("copy succeeded\n");
}
int main(int argc, const char* argv[]){
//文件IO:文件描述符
int file_ori_des = open("./01_fork.c",O_RDONLY);
int file_new_des = open("./01_new_fork.c",O_WRONLY|O_CREAT|O_TRUNC,0777);
int len = lseek(file_ori_des,0,SEEK_END);
pid_t pid = fork();
if(pid>0){ //父进程
//sleep(1);
wait(NULL);
RD_WR(0,len/2,file_ori_des,file_new_des);
}else if(pid==0){
RD_WR(len/2,len,file_ori_des,file_new_des); //子进程
exit(0);
}else if(pid==-1){ //error
ERROR("");
}
return 0;
}
结语
以上