嵌入式学习 day31:进程与线程
一、进程的基本概念
1.1 程序 vs 进程
| 程序 | 进程 | |
|---|---|---|
| 定义 | 存放在外存中的代码集合 | 程序动态执行的过程 |
| 本质 | 静态的(文件) | 动态的(运行中) |
| 生命周期 | 持久(直到被删除) | 创建→调度→消亡 |
程序是写在硬盘上的代码文件,进程是程序被加载到内存中运行起来的实例。一个程序可以同时运行多个进程(比如开多个终端窗口)。
1.2 进程相关命令
| 命令 | 作用 |
|---|---|
ps -ef |
查看所有进程信息 |
ps -aux |
查看进程运行状态 |
pstree |
查看进程树(父子关系) |
top |
动态查看进程CPU/内存占用 |
kill -9 PID |
强制杀死进程 |
killall -9 进程名 |
按名字杀死进程 |
jobs |
查看后台任务 |
fg 编号 |
将后台任务调到前台 |
后台运行程序:
bash
./a.out & # 后台运行 jobs # 查看后台任务 fg 1 # 将任务1调到前台
二、进程ID(PID)
每个进程都有一个唯一的整数编号——PID。可以通过 getpid() 获取当前进程的PID,getppid() 获取父进程的PID。
c
#include <stdio.h>
#include <unistd.h>
int main(void)
{
printf("PID: %d\n", getpid());
printf("PPID: %d\n", getppid());
return 0;
}
运行结果:
text
PID: 12345 PPID: 23456 // 父进程通常是shell(终端)
三、进程的创建 —— fork()
fork() 是创建新进程的核心函数。调用一次,返回两次:
c
#include <stdio.h>
#include <unistd.h>
int main(void)
{
pid_t pid = fork();
if (pid == -1) {
perror("fork");
return -1;
}
if (pid == 0) {
printf("子进程:PID=%d, PPID=%d\n", getpid(), getppid());
} else {
printf("父进程:PID=%d, 子进程PID=%d\n", getpid(), pid);
}
return 0;
}
fork() 的返回值:
| 返回值 | 含义 |
|---|---|
-1 |
创建失败 |
0 |
当前在子进程中 |
>0 |
当前在父进程中,返回值是子进程的PID |
四、进程的退出 —— exit()
进程结束时要释放资源,exit() 负责这个事。
c
#include <stdlib.h> void exit(int status);
-
status是退出状态码,父进程可以通过wait()获取 -
0 通常表示正常退出,非0表示异常
-
exit()会自动刷新缓冲区、关闭打开的文件
c
exit(0); // 正常退出 exit(1); // 异常退出
注意:return 只结束当前函数,exit() 结束整个进程。
五、等待子进程 —— wait()
父进程创建子进程后,通常需要等待子进程结束,获取它的退出状态。如果不调用 wait(),子进程结束后会变成僵尸进程。
c
#include <sys/wait.h> pid_t wait(int *status);
c
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(void)
{
pid_t pid = fork();
if (pid == 0) {
printf("子进程开始\n");
sleep(2);
printf("子进程结束\n");
exit(10);
} else {
int status;
pid_t ret = wait(&status);
printf("父进程:子进程 %d 退出,状态码 %d\n", ret, WEXITSTATUS(status));
}
return 0;
}
wait() 的返回值:成功返回结束的子进程PID,失败返回 -1。
解析退出状态:
| 宏 | 作用 |
|---|---|
WEXITSTATUS(status) |
获取子进程的退出码 |
WIFEXITED(status) |
判断子进程是否正常退出 |
c
if (WIFEXITED(status)) {
printf("正常退出,退出码:%d\n", WEXITSTATUS(status));
}
六、孤儿进程与僵尸进程
孤儿进程:父进程先于子进程结束,子进程变成孤儿,被 init 进程(PID=1)收养。
僵尸进程:子进程已结束,但父进程没有调用 wait() 回收资源,导致子进程的进程表项一直占用。
僵尸进程不占用内存,但占用进程表资源。如果大量僵尸进程积累,可能导致系统无法创建新进程。
七、今日总结
今天学了进程,核心要点如下:
-
程序 vs 进程:程序是静态文件,进程是动态执行实例
-
PID:
getpid()获取当前进程ID,getppid()获取父进程ID -
fork():创建子进程,返回0表示子进程,>0表示父进程
-
exit():结束进程,刷新缓冲区、关闭文件
-
wait():父进程等待子进程结束,回收资源,防止僵尸进程
-
孤儿进程:父进程先结束,子进程被 init 收养
-
僵尸进程:子进程先结束,父进程未回收,占用进程表资源
今日感悟:
今天第一次感受到"一个程序可以分成多个进程同时执行"。fork() 调用一次返回两次的特性,让父子进程能各自独立运行。另外,一定要记得使用 wait() ,否则子进程结束没人“收尸”,就成了僵尸进程。
更多推荐

所有评论(0)