系统调用和进程

系统调用

 常用的系统调用

cout,printf都是最常用的系统调用,因为用户输出使用到了显示器

 

系统调用接口

站在开发者的角度,可以直接调用系统接口,将系统接口封装成各种各样的函数,打包成函数库

,所有开发者直接调用库函数

进程

什么叫做进程?

进程=可执行程序+内核数据结构(PCB),也是管理操作系统内任务的一种方式

进程vs程序

将一个程序编译好了放在了磁盘上就是程序,将一个可执行文件从磁盘加载到内存里就是进程,操作系统可能会同时存在非常多的“进程“,操作系统要不要管理所有的进程呢?如何管理?先描述,再组织。操作系统是用c语言写的,要描述的肯定是进程

PCB

首先操作系统先将硬盘上的数据拷贝到内存中,然后再创建pcb链表,将他们一个一个链接起来,形成了pcb链表,cpu查看哪个pcb的优先级高,cpu就讲那个所对应的文件放入到cpu中,如果不需要该进程了,则销毁从硬盘中拷贝到内存的数据,再将该进程所对应的pcb给删除,所以对进程的管理就变成了对链表的增删改查 

  

状态:状态决定要干什么

linux中,进程PCB具体是strcut task_struct(),这里面包含了进程的各种属性,struct dlist list。

strcut task_struct(){
dlist list//可以在列表里
dlist queue//这个进程也可以在队列中
也可以在其他各种结构中
}

pcb可能在各种结构里

task_struct核心字段

pid

pid  进程(任务)对应的标识符:pid(process id)

查看进程的第一种方式:ps ajx

也就是说我们所运行的软件,程序,指令都是进程 

查看进程的第二种方式proc

linux中一切皆文件,所以进程也有相应的映射文件,在proc这个文件里面,动态的进程根据进程的进程号可以显示在当前文件夹中,当进程结束时,该进程号就会销毁,也就是查不到该进程号

进程的工作目录

默认情况下,进程启动所处的路径就是当前路径。

当我们写入一个文件时,总是默认写到当前的路径下

 也可以调用chdir函数去修改目录,我们将路径更改到该路径下后gcc会发现109.txt在该目录下创建了, 

 我们在pcb中也可以查到该进程所对应的工作路径,由此可知pcb中记录了该进程的工作路径 

fork

先说结论:fork进程是创建一个子进程,该子进程在函数调用前不创建,只执行父进程,但是在函数调用后父子进程都要执行。  

fork原理

1.fork干了什么事情?

一个文件的使用必须从磁盘上加载到内存,那么就会产生相应的pcb,而fork创建了一个子进程,该进程会创建一个自己的pcb,pcb中的内容会写实拷贝父进程的内容,该进程的父进程则是原来被写实拷贝,子进程则返回0,由于该子进程是由父进程创建来而非从磁盘加载来,则需要拷贝父进程中的代码过来,他们的代码是共享的,但是相互独立,各自持有一份,父进程kill了,子进程不会kill,同样子进程kill了,父进程不会kill。

2.fork为什么会有两个返回值

fork让父进程分流了,则出现了两个pcb,各自执行自己的语句,最后会return两次,所以产生两个返回值 。

3.为什么fork的父进程返回子进程的pid,子进程返回0?

因为父进程需要表示到子进程的pid才能找到子进程,而子进程不需要标记到父进程,父和子的关系相当于1:n,子只有一个父,所以是唯一的标识,而父不一定只有一个子,所以子需要有唯一标识。

4.父子谁先运行?

不确定的,是根据调度细节来决定的,

kill -9

杀死进程号,结束该命令

ppid(父进程)

 在linux中,登陆之后,父进程就一直保持不变了,所以在linux中父进程一般是命令行解释器,也就是bash,我们平常创建进程的方式有命令行中直接启动,通过代码创建进程,启动进程,本质就是创建进程,我们启动命令行就是创建bash的子进程。

通过getppid调用父进程,通过getpid调用进程

 父进程在登陆后都是相同的,但是同一个程序的进程可能会每次调用的时候进程号不一样了

操作系统上的进程状态

就是pcb的一个字段,就是pcb的一个变量,int status,也就是pcb->status=new。

本质:

更改pcb status整数变量

将pcb连入不同的队列中

运行状态

内存中的struct runqueue中有num,pcb *head,只要在运行队列中的进程,他的状态都是运行状态,代表了已经准备好了,可以随时被调度,每一个cpu在系统层面上都为维护一个运行队列

阻塞状态

假设我们使用cin函数,那么我们编译后不输入任何东西,那么就卡在了那里,就是被阻塞了。为什么卡住了?pcb没在运行队列中,状态不是在runnning,cpu不调度你的进程了。在操作系统中会存在非常多的队列,运行队列,等待队列,设备也有自己的队列。

挂起状态

如果一个进程当前阻塞了,这个进程在它所等待的资源没有就绪的时候,该进程是无法被调度的,如果此时,os内存不足了怎么办?

将内存的数据进行置换到外设,针对所有阻塞进程。swap分区,os的数据会交换到这里,当进程被os调度,曾经被置换过去的进程代码和数据,又被重新加载进来。以上这些操作全是用操作系统自动运行

linux中的进程状态

linux中的进程状态有特定字母去表示

R(running)

一个进程在运行队列中,在一定意义上称为就绪或者运行状态

S(sleeping)

休眠状态,浅度睡眠可以被终止,会对外部的信号做出响应,比如等待输入就会进入休眠,也就是阻塞状态

D(disk sleep)

也是休眠状态,称为深度睡眠,专门针对磁盘来设计的,不可以被杀掉,操作系统也没资格杀掉该资源,针对i/o状态的休眠,也是一种阻塞状态

T(stopped)

在软件访问资源的时候,我们进行暂停,不让进程进行访问

t(tracing stop)

debug的时候,追踪进程,遇到断点,就暂停了

X(dead)

任何进程都会有死亡状态,一个进程死亡状态有很多预处理,当进程退出时,将pcb和自己的代码和数据在内存中释放掉

为什么要创建进程?一定是要完成某种任务,进程在退出的时候要有一些退出信息,表明自己把任务完成的怎么样,该信息会记录在pcb中,也就是有了退出信息,比如main函数最后会有return 0,当一个函数需要退出的时候,会将main函数的return 0记录在pcb中,也就是将退出进程写到pcb中,可以允许进程的代码和数据被释放,但是不能允许pcb被立即释放,父进程需要读取进程的pcb退出信息,读取了子进程的原因。 

Z(zombie)

进程退出了,父进程还没有被父进程和os读取,os还必须维护退出进程的pcb结构,该进程算退出了,属于僵尸状态。父进程或者os读取后,pcb先被修改成x,才会被释放。如果父进程或者os一直不回收,pcb就一直会存在,也就是内存泄漏

孤儿进程

父进程退出了,子进程还在就叫孤儿进程,此时子进程就要被1号进程给领养,也就操作系统(initd/sysemd)

defunct代表了进程已经死亡

进程的优先级

优先级存在的本质就是因为资源不足,本质就是得到某种资源的先后顺序。优先级在在pcb中映射就是int字段priority,数值越小,优先级越高。linux进程中优先级范围一般在60-99,默认情况下是80。

nice值

linux是支持动态优先级调整,但是不允许直接改优先级数字,所以pcb中会存在nice值:进程优先级的修正数字,pri(new)=pri(old)+nice。

nice值调整最小是-20,最大是19。超过按-20/19处理。优先级越高得到资源就越强,os调度的时候,应该均衡的让每个进程都得到调度,如果进程将自己的优先级调的很高,那么优先级较低的进程就会得不到cpu资源,也就是进程饥饿问题

指令top->r->pid->nice值->修改成功

并行

多个进程在多个cpu下分别,同时运行,叫做并行

并发

多个进程在一个cpu下采用进程切换的方式,在一段时间内让多个进程同时推进,就叫做并发。

每个进程不是占有cpu一直运行,每隔一段时间就自动从cpu上剥离下来。linux中cpu资源的争夺是基于时间片轮转的抢占式内核。

栈临时变量

cpu中只有一套寄存器,但是有多套寄存器数据。将cpu中的数据保存到pcb中,本质上是把cpu中的内容保存到内存中。

进程切换

每次切换的时候eax,eip等寄存器数据都保存到pcb中,需要用的时候再去取数据,用完再拷贝回去,这样就形成了并发的进程切换  

linux2.6调度队列原理

在2.6的runqueue中有两个进程,一个是活跃进程(active),一个是过期进程(expired),分别用两个指针指向这两个queue。活跃进程代表已经准备好并且跑的,过期是代表等待跑的,优先级有60-99,在queue中映射到下标100-139,后面来的全都添加到expired中,不再加入active。等active全部处理完,交换expired和active的指针,其中bitmap代表位图,分别映射100-139中为不为空,如果为空则跳过,这样的好处是加快了queue的遍历速度。 

命令行参数

命令行参数是支持各种指令识别的命令行选项的设置

命令行参数也是父进程,你所有的环境变量都是从bash那边拿过来的

main函数中的命令行参数

main函数中的命令行参数最多有三个,其中第三个命令行参数就是环境变量env,这是一个数组指针,指向最后一个

环境变量

系统中会存在大量的环境变量,每一个环境变量会用来完成特定的系统功能,任何的指令都是环境变量

路径设置 

追加路径

在 

安装程序和卸载程序本质上就是简单的拷贝

当我们登陆的时候输入用户名密码后认证,根据用户名初始化HOME目录,此时所处的路径就是当前用户家目录  

env

查看bash当前所有的环境变量

环境变量参数

getenv()

获得该环境变量存放的地址

局部变量

全局变量

每一个环境变量最初都来在操作系统,操作系统再给bash,所以环境变量通常有全局属性。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值