进程初步2
目录
进程初步2
1、进程等待清理函数(wait)
2、等待指定的子进程(waitpid)
3、新的开辟进程的函数(vfork)
4、在程序中运行系统下的指令(system)
5、exec 函数族
例题:
tip1:特殊进程
0号进程
祖先进程
孤儿进程
僵尸进程
tip2:
1、进程等待清理函数(wait)
-- 函数头文件
- #include <sys/types.h>
- #include <sys/wait.h>
-- 函数原型
- pid_t wait(int *wstatus);
-- 函数的作用:
- 阻塞当前进程 等待子进程死亡
- 子进程死亡 解除阻塞 并执行资源的回收
- 获取子进程的退出状态
-- 函数的参数:
- int *wstatus:用来接收子进程的退出状态
- 子进程调用exit函数进行退出的参数会放到这里
- 通过宏定义可以判断是否为正常退出
- WIFEXITED(wstatus)
-- 返回为真 进程为正常结束 如:exit、_exit、 main函数的return
-- 返回为假 非正常结束 如:段错误、 kill 等 - WEXITSTATUS(wstatus)
-- 可以将子进程exit中的参数解出来
-- 函数的返回值:
- 成功返回 死亡的子进程的进程号
- 失败返回 -1
2、等待指定的子进程(waitpid)
-- wait函数等待的任意一个子进程,谁先死,先执行那个,而下面这个函数可以等待具体哪个进程。
- pid_t waitpid(pid_t pid, int *wstatus, int options)
-- 函数的作用:
- 根据参数的填写 进行相应的等待函数操作
- 判断子进程的状态 是否死亡是否为正常退出
- 获取子进程的返回值
-- 函数的参数:
- pid:填写要进行等待的指定子进程进程号
- -1:任意的一个子进程
- ‘>0’:指定的子进程
- wstatus:用来存放子进程的退出状态以及返回值
- options:填写是否阻塞等待
- 0:阻塞等待
- WNOHANG:非阻塞
-- 函数的返回值:
- 成功返回 死亡的子进程的进程号
- 失败返回 -1
3、新的开辟进程的函数(vfork)
-- 函数的头文件
- #include <sys/types.h>
- #include <unistd.h>
-- 函数的原型
- pid_t vfork(void);
-- 函数的作用:
- 创建一个新的子进程并阻塞父进程
- 子进程共用父进程的资源空间
- 子进程退出之后 父进程开始运行
- 运行顺序 子先父后
-- 函数的返回值:
- 子进程中返回 0
- 父进程中返回 子进程进程号
注:使用vfork子进程如果使用main函数中的return会出现段错误
我们需要在子进程中,使用_exit来进行退出 或者使用exec函数族来实现
4、在程序中运行系统下的指令(system)
-- 函数头文件
- #include <stdlib.h>
-- 函数原型
- int system(const char *command)
-- 函数的作用:
- 运行系统下的指令
-- 函数的参数:
- command:要运行的指令
-- 可以执行系统命令,主要原理是创建一个子进程,用exec函数族中的其中一个函数执行系统命令
-- 所以可以用fork函数和exec函数族中的函数写出来达到system函数的作用
5、exec 函数族
-- exec函数族中的函数功能效果是完全一样的,只是传参不同,所以只需要记住一个函数原型即可。
-- 主要用来执行系统下的指令 或者 程序
-
#include <unistd.h>
-
int execl(const char *pathname, const char arg, ... / (char *) NULL */);
-
int execlp(const char *file, const char arg, ... / (char *) NULL */);
-
int execle(const char *pathname, const char arg, ... /, (char *) NULL, char *const envp[] */);
-
int execv(const char *pathname, char *const argv[]);
-
int execvp(const char *file, char *const argv[]);
-
int execvpe(const char *file, char *const argv[], char *const envp[]);
-- 以上函数的作用:
- 1 写在这些函数下面的内容就不会运行了 这些函数会将程序的原本内容进行替换
- 2 他会获取新的空间资源 但是原本的进程号不变
-- int execl(const char *pathname, const char arg, ... / (char *) NULL */);
- pathname:填写要运行的文件的绝对路径
- arg:要运行的指令
- arg1: 选项 和参数 等内容
- 以 NULL 结尾
-- 并且在子进程中执行execl函数时,父进程是非阻塞的状态。
-- int execlp(const char *file, const char arg, ... / (char *) NULL */);
- file:直接给指令名称
- arg:指令
- argx:参数和选项
- 以 NULL 结尾
- 例如:execlp("ls","ls","-l",NULL);
-- int execv(const char *pathname, char *const argv[]);
- pathname:指令所在的绝对路径
- argv:指向运行的内容
- char * a[] = {"ls","-l",NULL};
- execv("/bin/ls",a);
例题:
-- 实现自动循环播放音乐
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
//实现自动循环播放音乐
int main(int argc, char const *argv[])
{
int n=0;
while(1){
n++;
pid_t pid = vfork();
if(pid == 0){ //子进程
printf("Im son\n");
switch(n)
{
case 1:execl("/bin/mpg123","mpg123","/home/pimouren/learn/系统编程/5 进程初步/music/benxi.mp3",NULL);
break;
case 2:execl("/bin/mpg123","mpg123","/home/pimouren/learn/系统编程/5 进程初步/music/daoxiang.mp3",NULL);
break;
case 3:execl("/bin/mpg123","mpg123","/home/pimouren/learn/系统编程/5 进程初步/music/苏打绿 - 小情歌.mp3.mp3",NULL);
break;
default:n=0;break;
}
}else if(pid > 0) // 父进程
{
printf("**********\n");
pid_t a = wait(NULL);
if(a == pid)
{
printf("音乐播放完毕,开启下一首\n");
}
}
}
return 0;
}
tip1:特殊进程
0号进程
- 操作系统的引导程序
祖先进程
- 操作系统启动的第一个程序,1号进程
孤儿进程
-
父进程先退出,子进程被init接管,子进程退出后init会回收其占用的相关资源
-
缺点:子进程的相关资源无法清理回收
僵尸进程
- 子进程先退出,父进程没有回收子进程的资源,导致子进程无法回收
-- 一种非常特殊的进程,它几乎已经放弃了所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间
tip2:
-- pstree 命令可以用来查看进程树,包括所有的子进程。它以树形结构显示当前系统中的进程及其父子关系,使得理解进程间的层级关系变得更加直观。
使用方法很简单,只需在终端中输入 pstree 命令即可。
-- 如果你想查看特定用户的进程树,可以使用 -u 选项,例如:
- pstree -u 用户名
-- 此外,你也可以使用 -p 选项来显示进程的 PID(进程ID):
- pstree -p
-- 如果你只想查看某个特定进程及其子进程,可以在命令后面加上该进程的 PID,例如:
- pstree -p 1234
-- 这将显示 PID 为 1234 的进程及其子进程的树形结构。