进程的一生

本文介绍了进程的创建(fork)、替换(exec函数族)、同步(互斥锁flock)、结束(exit,_exit)以及父进程如何回收子进程资源(wait,waitpid)。还涉及到了环境变量的临时和永久修改方法。
摘要由CSDN通过智能技术生成

进程的生老病死、收尸以及 不想死

注意啦:以下是本人介绍哦
📕作者简介: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

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

S安东尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值