社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
一、进程的概念
程序:代码+数据
进程:代码+数据+堆栈+PCB
程序:为了完成特定功能的一系列指令的有序集合
进程:一个具有一定独立功能的程序在数据集合上的一次动态执行过程
每个进程都有自己的状态
每个进程都有自己的虚拟地址空间
进程是操作系统分配资源的基本单位
组成:进程包含了一个程序执行过程中的所有状态信息
程序的代码
程序处理的数据
程序计数器中的
寄存器动态变化
系统资源
进程与程序的联系:
程序是进程的基础
程序每次执行构成不同的进程
进程是程序功能的体现
多次执行,一个程序可以应对多个进程,通过调用关系,一个进程可以包含多个程序(多对多)
进程与程序的区别
进程是动态的,程序是静态的,程序是有序代码的集合,进程是程序的执行,进程有核心态/用户态
进程是暂时的,程序是永久的,进程是一个状态变化的过程,程序可长久保存
进程与程序的组成不同,进程的组成包括程序、数据、和进程控制块
进程控制块(PCB---进程属性的集合)
进程信息被放在一个叫进程控制块的数据结构中,Linux中的PCB是:task_struct,它里面包含着进程的信息,并且会被装载到RAM内存中
task_struct内容
标识符:描述本进程的唯一标识符,用来区别其他进程
状态:任务状态,退出代码,退出信号等
优先级:相对于其他进程的优先级
程序计数器:程序中即将被执行的下一条指令的地址
内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块指针
上下文数据:进程执行时处理器的寄存器中的数据
I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用文件列表
记账信息:可能包括处理时间总和,使用的时钟数总和、时间限制、记帐号等
其他信息
调度:优先级、动态变化
从就绪中的程序中选择合适的放在CPU中执行
二、进程相关操作命令
cat /proc/sys/kernel/pid_max:系统ID号最大值
ps:报告系统当前进程
ps -ef
df:查看磁盘情况
df -ef
ps -ef | grep a.out |grep -v grep反向过滤
三、创建一个进程的一般工作
1.分配一个PID(从小到大找第一个没有被使用的ID)
【0—cat /proc/sys/kernel/pid_max】
0号进程是内核进程,它创建1号进程。
0号进程还将进程从物理内存搬到磁盘,和从磁盘搬到物理内存
2.分配PCB,拷贝父进程的PCB的绝大部分数据
3.给子进程分配资源
4.复制父进程地址空间
5.将子进程制成就绪状态放入就绪队列
6.pid_t fork(viod) 子进程0,父进程大于1
子进程是父进程的翻版,子进程具有父进程的栈、数据段、堆和执行文本段的拷贝。
父进程和子进程有相同的程序文本段,但各自拥有不同的堆栈、数据段、堆段拷贝
执行fork( )后每个进程均可修改自己的栈数据、堆段中变量,而不影响另一进程
pid_fork (void);
作用:创建一个进程
返回值:子进程返回0;父进程返回大于0(实际上就是子进程的PID);当前无法创建时返回-1
1.创建后,父子进程交替进行(0为子进程,父进程大于1)
2.若父进程死亡,子进程变为孤儿进程,由1号进程领养
3.若子进程死亡,成为僵尸进程
fork()创建的子进程是对父进程的栈、数据段、堆和执行文本的拷贝,但是这样做会浪费内存空间。避免这种浪费有两种方法:
1、内核将每一个进程的代码段标记为只读,从而使进程无法修改自身代码,这样子进程和父进程可以共享同一代码段,指向相同的物理内存页帧
2、对于父进程数据段、堆段和栈段的各页,内核采用写时复制技术,起初内核将进程的代码段标记为只读,使父进程和子进程指向相同的物理内存,调用fork()后内核会捕获所有子进程和父进程对代码段的修改企图,然后将要修改的代码段拷贝分配给造内核捕获的进程,之后父进程和子进程就可以修改各自的代码段拷贝,不再相互影响。
fork和vfork
fork是创建一个子进程,并把父进程的内存数据copy到子进程中。
vfork是创建一个子进程,并把子进程 和父进程的内存数据share一起共用
vfork不进行写时拷贝,性能相较于fork更好,但是vfork的实现在每个系统上面都存在错误,只有在vfork调用完后加上exec或者exit才会正确。
getpid()可以获取进程的PID;getppid()可以获取进程的父进程的PID
创建一个孤儿进程
创建一个僵尸进程
僵尸进程是不能用kill被杀死的,从系统中移除其的唯一方法就是杀掉他们的父进程(或等待其父进程终止),此时init将接管和等待这些僵尸进程,将它们清除掉。
当创建的僵尸进程过多的时候会导致以下问题:
造成内存资源的浪费
内存泄漏
维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说,僵尸状态一直不退出,PCB一直都要维护
四、进程的优先级
ps -l(查看当前系统进程的优先级)
UID 执行者身份
PID 进程ID
PPID 父进程ID
PRI 进程可被执行的优先级,其值越小越早被执行
NI 进程的nice值
子进程会继承父进程的优先级,因为PCB中存储着进程的优先级,创建子进程的时候会将父进程的PCB拷贝过来。
进程的nice值
概念
取值范围
nice取值范围:-20-19,总共40个级别
nice值的修改
PRI(new)=PRI(old)+nice
如:renice -5 -p 2600(将PID为2600的进程nice值修改为-5)
如:nice -n -5 ./test (开始执行指定nice值的进程)
在进程启动之前可以通过nice来调整进程的优先级
当nice的值为负值的时候,该程序的优先级值将会变小,其优先级会变高,会越快被执行。
用top命令修改已存在进程的nice
top可以查看系统所有进程的相关信息,相当于Windows的任务管理器
进程的并行和并发
并行:多个进程在多个CPU下分别同时运行
并发:多个进程在一个CPU下采用进程切换的方式,在一段时间内,让多个进程都得以推进,一个CPU只能在某个时间内运行一个进程,不能多进程同时运行
多进程程序只可能是并行的不可能是并发的
五、环境变量
环境变量在命令行参数和PCB之间
本地变量和环境变量:
本地变量只能在当前进程使用,不能在子进程中使用
父进程定义的环境变量能在当前进程和子进程中使用
子进程定义的环境变量只能在子进程使用,不能在父进程中使用
环境变量相关指令:
export name=val (定义环境变量,=左右不能加空格)
unset avj(删除环境变量)
env 获取全部环境变量
echo $环境变量名 打印出相对应的环境变量值
unset:可以删除本地变量
设置环境变量:
当前终端设置的环境变量只能在当前终端使用,离开就没有了,且只能在当前终端当前用户下使用
如果想所有地方都能使用环境变量需要配置在 ~/.bash_profile
如果希望在配置文件中设置的变量生效,要重启(在终端启动之前会执行~/ .bash_profile和~/ .bashrc这两个文件里的内容)
在程序中获取环境变量:
获取所有的环境变量,main的第三个参数
获取某一个环境变量,val=getenv(“name”)
在程序中设置环境变量 ,putenv(“name=value”)等号左右不能有空格
查看进程树 pstree
查看进程树中bash及其前两行后两行 pstree |grep -A2 -B2 “bash”
六、程序地址空间
子进程是父进程的拷贝,当子进程修改时,先将值拷贝到另一块物理内存中,将页表中的只读改为可读可写,再修改值
因此,修改后父子进程虚拟地址相同,物理地址不同
错误处理
linux绝大部分函数出错返回值都是-1
int errno;//linux函数出错后将错误编号放在errno全局变量中
if(fork()==-1)
errno(错误码编号)
#include<errno.h>
char* strerror(errno);通过错误编号,返回错误信息
#include<string.h>
printf("%s",strerror(errno));打印错误信息
perror(cmd="fork")
{
printf("%s : %sn",cmd,strerror(errno));
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!