Linux进程篇

进程概念

1.冯诺依曼体系
冯诺依曼:计算机之父,数学家,物理学家,化学家(曼哈顿计划–原子弹计划)
Linux进程篇

冯诺依曼提出中央处理器,内存,输入输出设备的概念。这里我们需要了解一下二进制和内存系统的概念。
二进制:所有的数据都是按照二进制的方式进行存储
内存系统:由存储器设备来存储需要计算的内容和计算完毕之后的内容
2.操作系统
2.1什么是操作系统
操作系统也是一个软件。操作系统=操作系统内核(操作系统管理计算机资源的代码)+一组应用
管理=描述(struct)+组织(双向链表),所以操作系统通过描述+组织的方式来管理操作系统的软硬件资源
Linux进程篇
3.进程概念
1.程序和进程的区别
程序本质上是一个普通文件,通常将编译完成之后产生的可执行文件称为程序,程序是静态的。进程是程序执行起来的一种表现形式,内核观点:进程是操作系统分配资源(程序地址空间)的最小单位。
2.操作系统是如何来管理进程
描述:Linux操作系统使用进程控制块来描述我们的进程。进程控制块:本质上是一个结构体,struct task_struct{…};别名PCB(process control block)task_struct:进程标识符又称进程pid
Linux进程篇
当一个程序启动时,操作系统内核会维护一个task_struct这样一个结构体,并且在/proc/[pid]文件夹保存与当前进程相关的文件。这个/proc/[pid]的文件夹,当进程运行的时候会存在,当进程退出的时候,就会被操作系统清理。防止文件句柄泄露。
4.进程状态
运行状态:进程拥有cpu,在进行计算
就绪状态:在就绪队列中等待cpu资源的进程状态称为就绪状态
阻塞状态:等待IO,进行数据输入,如果一直没有准备好数据,当前进程一直处于阻塞状态(死等状态)
运行状态R(Running):1.拿着cpu进行运算2.在就绪队列当中
可中断睡眠状态S(Sleeping)
磁盘睡眠状态D(Disk Sleep):不可被打断
暂停状态T(Stoped):ctrl+z使得一个程序变成暂停状态,kill [pid]并不会杀死一个暂停状态的进程,但kill -9 [pid]可以杀死
跟踪状态t(trace stop):gdb调试的时候产生的状态
死亡状态X:程序员是看不到的,在进程退出的时候才能看到死亡状态,在task_struct中存在
僵尸状态:当子进程退出,但父进程来不及回收就产生了僵尸状态,即使用kill -9 [pid]也无法结束进程
前台进程:在命令行中启动一个程序的时候,不能输入命令,输入无效的穷狂下,我们称之为前台进程,用ctrl +c可以结束前台进程,或者使用kill [pid]来结束。用fg可将后台进程放到前台来运行,在执行ctrl +c来结束。
万恶之源:多个进程之间对于cpu是抢占式执行的
并发执行:多个进程使用同一个cpu,每一个进程都会独占cpu一会,然后让出cpu供其他进程使用
并行执行:多个进程每一个进程都占有一个cpu进行运算
5.进程切换
程序计数器:保存进程即将要执行的下一条指令
上下文数据:保存上次执行的时候,寄存器当中的值
内存指针:指向虚拟地址空间
IO信息&记账信息:当前进程的启动时间,当前进程占用cpu的时间、
优先级:相对于其他进程的优先级,PR(new)=PR(old)+NI,但有点鸡肋,因为一切解释权归操嘴系统所有。
6.如何在代码中创建一个进程
系统调用:pid_t getpid(void)获取当前进程的pid接口
系统调用:1.int fork()用来创建进程。返回值:成功的话返回两个返回值,返回子进程pid给父进程,返回0给子进程,失败则返回小于0得数。返回两次对于代码编写的直观意义便是可以使用分支语句去区分父子进程而执行不同的逻辑。
Linux进程篇
创建的子进程与父进程代码共享,但数据独有。如上图虽然代码相同但执行的逻辑不同。
这里有一个孤儿进程的小知识。孤儿进程:父进程先于子进程退出,子进程被一号进程所领养(一号进程:操作系统启动的第一个进程,好多进程都是被一号进程所创建的),进程有僵尸状态的,但没有孤儿状态。
僵尸进程如何回收:1.杀死僵尸进程的父进程(不推荐)2.进程等待时解决。
Linux进程篇
2.int vfork(void):vfork创建出来的子进程拷贝部分父进程的pcb,共用同一个虚拟地址空间,但存在调用栈混乱的问题,所以vfork先让子进程执行,父进程等待子进程执行完毕后再执行,这样很麻烦,所以vfork函数创建子进程已经被淘汰了。

接下来介绍计算进程虚拟地址的三种方法:
分页式

Linux进程篇
分段式
Linux进程篇
段页式
Linux进程篇

7.环境变量
环境变量是用来定义系统运行环境的一些参数。注意:环境变量名称一般都是大写。
常见的环境变量:
HOME:保存用户家目录的环境变量
SHELL:保存当中使用的命令行解释器的名称
PATH:保存可执行程序路径的环境变量
LD_LIBRARY:程序运行时,依赖库文件的搜索路径的环境变量
CPLUS_INCLUDE_PATH:可以定义第三方C++头文件所在路径的环境变量
常见命令
echo []envexportexport[]=[环境变量名称]:可以查看某一个环境变量的值 env:可以查看当前操作系统当中环境变量的名称及值 export:可以更改或者增加环境变量,在命令行当中直接运行则是临时生效,export [环境变量名称]=[环境变量名称]:[新加的环境变量的值],想要永久生效,则需要将更改环境变量的内容写到环境变量文件(~/.bashrc)当中去,每次重新打开一个终端,操作系统都会帮我们加载环境变文件,从而更改的换进变量内容也被加载到黄金变量当中去了。
使环境变量当中的值生效:source[更改环境变量的文件]或者重新打开一个新的终端。两种做法都会重新加载所有的换进变量文件。
8.进程终止
1.含义:进程终止的含义就是一个进程的退出
2.场景:
(1)程序跑完了所有的代码,从main函数退出,代码跑完,结果正确;或者代码跑完,结果不正确。
(2)程序没有跑完所有代码,程序崩溃掉了
3.退出的方法
Linux进程篇

退出码:函数在退出的时候,返回的值,来源于main的返回值,或者exit的参数,可以使用echo $?查看上一次的退出码
(1)main函数的return返回
(2)exit库函数
(3)_exit:系统调用函数(这个函数相对于exit函数少执行了用户自定义的清理函数和冲刷缓冲区关闭流两个步骤)
Linux进程篇

用户自定义的清理函数:int atexit(void (function)(void))函数参数是一个函数指针,可以接受没有返回值,没有参数的函数地址。调用atexit函数,就爱那个参数传入的函数地址告诉内核。当程序需要退出的时候,才调用传入的函数,这样的函数叫做回调函数。
·
9.进程等待
阻塞:当调用函数需要等待一定条件成熟的时候,成熟则返回,如果条件一直不成熟,则一直等待
非阻塞:当调用函数需要等待一定条件成熟的时候,,成熟则返回,条件不成熟,也报错返回。
1.为什么需要进程等待呢?
进程等待的原因就是为了防止产生僵尸进程
2.进程等待有哪些方法呢?
(1)pid_t wait(int status)阻塞接口 status是一个出参,供调用wait函数的进程获取子进程退出信息的
(2)pid_t waitpid(pid_t,int status,int options)
pid:需要等待子进程的进程号,pid==-1表示等待任意的子进程,pid>0表示等待特定的子进程。
status:子进程推出信息
options:设置waitpid是阻塞还是非阻塞(WNOHANG非阻塞,0阻塞)在这里非阻塞一般搭配循环去使用。
waitpid(pid>0,status,0)相当于wait接口,wait接口实现就是调用waitpid实现的
10.进程程序替换
1.原理:替换数据段,代码段
Linux进程篇
2.进程程序替换接口
exec函数簇:不是一个函数,而是多个函数
int execl(const char path,const char arg,…)

path:带路径的可执行程序
arg:给可执行程序传递参数,规定:第一个参数必须是可执行程序的名称
…:可变参数列表,必须以NULL指针结尾,告诉execl函数读到NULL的时候,就是命令行参数结尾的地方
返回值:只有替换失败的时候才有返回值,返回-1,替换成功了,则直接执行替换的程序了
int execlp(const char file,const char arg,… )
*
file:可执行的程序名称,可执行程序时必须在环境变量PATH当中可以找到的,也可以直接传入可执行程序的绝对路径
arg:给可执行程序传递参数,规定:第一个参数必须是可执行程序的名称
…:可变参数列表,必须以NULL指针结尾,告诉execl函数读到NULL的时候,就是命令行参数结尾的地方
exec函数带p和不带p的区别:如果带有p,则表示ecevlp函数会搜索环境变量
int execle(const char path,const char arg,…,char* const envp[])**
path:带路径的可执行程序
arg:可执行程序的参数,NULL结尾
envp:程序员自己组织的环境变量,如果不传入环境变量则认为当前进程没有环境变量,如果自己组织环境变量,一定要以NULL结尾,否则就会报错Bad Address
带e和不带e的区别:如果不带e,则不需要程序员去组织环境变量,内核会将环境变量继承下来。如果带e,则需要程序要自己去组织环境变量,如果程序员传入NULL,则替换的程序中没有环境变量,如果传入非NULL,则指针数组的环境变量需要使用NULL结尾
int execv(const char path,char argv[])定参的函数
path:带路径的可执行程序
argv:给可执行程序传递参数,规定:第一个参数必须是可执行程序的名称,必须以NULL结尾
int execvp(const char path,char const argv[])

file:可执行的程序名称,可执行程序时必须在环境变量PATH当中可以找到的,也可以直接传入可执行程序的绝对路径
argv:给可执行程序传递参数,规定:第一个参数必须是可执行程序的名称,必须以NULL结尾
int execve(const char filename,char const argv[],char* const envp[])唯一一个系统调用函数**
filename:可执行程序的名称
argv:给可执行程序传递参数,规定:第一个参数必须是可执行程序的名称,必须以NULL结尾
envp:程序员自己组织的环境变量,如果不传入环境变量则认为当前进程没有环境变量,如果自己组织环境变量,一定要以NULL结尾,否则就会报错Bad Address
exec函数簇当中带有l和带有v的区别
l:表示命令行参数为可变列表 v:表示命令函参数为指针数组
Linux进程篇
先总结这些吧!