进程的生老病死、收尸以及 不想死
注意啦:以下是本人介绍哦
📕作者简介:S学长,致力于C/C++、嵌入式。从事嵌入式行业,热爱健身,身体倍棒的一位博主。
📗本文收录于嵌入式学习系列,大家有兴趣的可以看一看
📘相关专栏C语言嵌入式开发、C语言入门系列等,日常Bug集期待你的指导。
📙S学长爱上Linux系列正在发展中,喜欢嵌入式的朋友们可以关注一下哦!
1>进程的生
fork()函数
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
功能:
创建子进程
参数:
void ->空
返回值:
创建成功:
父进程返回子进程PID号 >0
子进程返回0 ==0
失败:
返回-1,并设置错误码
fork的三层理解
第一层:
1>父子进程共享代码,但是彼此之间的空间独立
2>在进程正常结束时,容易产生语句割裂
第二层:
代码示例:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(){
//fork函数
pid_t pid;
pid=fork();//在这里产生父子进程,将会执行以下所有的代码
printf("诞生于1996,梦想当说唱领袖\n");
printf("pid=%d\n",getpid());
while(1){
}
return 0;
}
第三层:
父子进程正常情况i下会共同执行代码。
通过 fork()返回值
父进程 >0
子进程 ==0
代码示例:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(){
//fork函数的第三层
pid_t pid=fork();//开展父子进程
if(pid>0){
//父进程的操作
printf("我是嫩叠\n");
printf("父进程的PID号为:%d\n",getpid());
printf("其父进程的PID号为:%d\n",getppid());
printf("\n");
}else if(pid==0){
//子进程的操作
printf("我是嫩儿\n");
printf("子进程的PID号为:%d\n",getpid());
printf("其父进程的PID号为:%d\n",getppid());
}
while(1){
}
return 0;
}
观察上面示例,提出两个问题。
1>父进程的父进程是谁,ID号为啥是6994?
2>示例代码为啥要写while死循环?
答:1>父子进程的PID通常是连续的,父进程大于子进程,父进程的父进程PID其实是运行这个程序终端的PID。
干掉它,这个终端就会关闭
答:2>父子进程接触到return语句会退出程序,由于退出的时间不同,不同电脑运行程序的结果可能不同,加入while循环保证程序输出的准确性。
练习:创建进程链和进程扇
2>进程的老
进程内 程序的替换
exec()函数族
#include<unisd.h>
extern char **environ;
int execl(const char *path, const char *arg, ...
/* (char *) NULL */);
int execlp(const char *file, const char *arg, ...
/* (char *) NULL */);
int execle(const char *path, const char *arg, ...
/*, (char *) NULL, char * const envp[] */);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],
解析:
1>exec函数族一共有6个成员
2>exec函数族都是exec开头
不带p :根据路径来加载程序
带p :根据文件名来加载程序 默认路径:/usr/bin 和 /bin
带l :根据列举来加载程序
带v :根据数组来加载程序
带e :根据环境变量加载程序后传递某些数据
exec失败返回-1,并设置错误码
3>进程的病
互斥锁:为了避免多进程同时访问一个临时资源而设置出来的一种保护机制,可让临界资源封闭,仅允许一个进程访问或使用。
flock()函数
#include<sys/file.h.>
int flock (int fd ,int operation)
功能:
给文件上锁
参数:
fd:文件描述符
operation:锁的属性
LOCK_SH :共享锁 --->形成共享关系,不阻塞
LOCK_EX :互斥锁 --->形成互斥关系,会阻塞
LOCK_UN :解锁
LOCK_NB :不上锁
返回值:
成功返回0
失败返回-1,并设置错误码
4>进程的死
死亡
程序正常结束 -> 遇到 return
自杀 ->exit 和 _exit
被杀 -> kill
1>第一个
#include <stdlib.h>
void exit(int status);
功能:
结束进程
参数:
status:进程退出状态 ---->遗言
:根据个人使用习惯决定:
个人用法 获取用法
结束用法: -1 返回给系统:收尸
正常结束: 1
2>第二个
#include <unistd.h>
void _exit(int status);
功能:
结束进程
参数:
status:进程退出状态 ---->遗言
:根据个人使用习惯决定:
个人用法 获取用法
结束用法: -1 返回给系统:收尸
正常结束: 1
总结:
exit和_exit的区别:
exit在结束进程之前,会刷新缓冲区,将原本滞留在缓冲区的数据得到刷新
_exit直接结束进程,不做任何其他操作,缓冲区内数据会被系统清掉
3> return
在main函数中,通过return结束main函数,达到结束进程的效果。
5>进程的收尸
收尸操作
只能父为子收尸体
专业角度:资源回收
wait()函数
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
功能:
父进程阻塞等待子进程死亡后进行收尸操作
带阻塞功能
参数:
wstatus:子进程死亡时的状态
死亡信息: 保存在次低位地址上
返回值:
成功返回收尸的子进程PID号
失败返回-1,并设置错误码
waitpid()函数
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *wstatus, int options);
功能:
父进程阻塞等待子进程死亡后进行收尸操作 (精准)
带阻塞功能
参数:
pid:
>0 给特定的子进程PID 收尸
例子:waitpid(2305,...,...)
=0 给当前同一进程组下的所有子进程收尸
=-1 给任意子进程收尸,无论在哪里
<-1 给进程组ID |-pid| 下的 子进程 收尸
wstatus:子进程死亡时的状态
options:属性选择
0:阻塞等待
WNOHANG:不阻塞
WUNTRACED:死因调查 ------*返回子进程的死亡状态
WIFEXITED:如果子进程是正常死亡,则返回true
采用WEXITSTATUS(wstatus)去分析子进程死亡状态
WIFSIGNALED:如果子进程是被信号杀死的,则返回true
采用 WTERMSIG(wstatus)去分析子进程死亡状态
WIFSTOPPED(wstatus):如果子进程是因为信号而暂停,则返回true
采用WSTOPSIG(wstatus)去分析子进程死亡状态
进程组操作
获取组号
getpgid
#include <sys/types.h>
#include <unistd.h>
pid_t getpgid(pid_t pid);
功能:
获取某个进程的进程组ID号
参数:
PID:想要获知组号的进程PID号
返回值:
成功返回该进程的进程组号
失败返回-1,并设置错误码
设置组号
setpgid
int setpgid(pid_t pid, pid_t pgid);
功能:
设置某个进程的进程组
参数:
PID:给谁设置
pgid:设置到哪
返回值:
成功返回0
失败返回-1,并设置错误码
环境变量配置
1>临时修改:只需要测试软件时推荐 一次性的,只能在执行该命令的终端上生效
export PATH=$PATH:/home/farsight/Process/day2
PS:PATH--->针对文件的环境变量
LD_LIBRARY_PATH---->针对库的
2>永久修改:只对某个用户生效 ----墙裂推荐
1>修改用户的环境 : .bashrc
vim ~/.bashrc
2>在底行添加:
export PATH=$PATH:/home/farsight/Process/day2
3>永久修改:所有用户生效 --->直接修改系统文件 --->不推荐
sudo vim /etc/environment
在后面添加: /home/farsight/Process/day2