Linux进程概念
文章目录进程基本概念与基本操作描述进程-PCBtask_struct查看进程通过系统调用来获取进程标识符通过系统调⽤创建进程-fork初识进程状态进程状态查看Z-僵尸进程僵尸进程危害孤儿进程进程优先级基本概念查看系统进程PRI and NIPRI vs NI查看进程优先级的命令竞争、独⽴、并⾏、并发进程切换⼀个CPU拥有⼀个runqueue优先级活动队列过期队列active指针和expired指针总结环境变量基本概念常⻅环境变量查看环境变量⽅法和环境变量相关的命令环境变量的组织⽅式通过代码如何获取环境变量进程基本概念与基本操作程序的一个执行实例正在执行的程序等。担当分配系统资源的实体。描述进程-PCB进程信息被放在一个叫做进程控制块的数据结构中可以理解为进程属性的集合。称为PCB(process control block),Linux操作系统下的PCB是task_struct在Linux中描述进程的结果体叫做task_structtask_struct是Linux内核的一种数据结构他会被装载到RAM里并且包含着进程的信息。task_struct标识符描述本进程的唯⼀标⽰符⽤来区别其他进程。状态: 任务状态退出代码退出信号等。优先级: 相对于其他进程的优先级。程序计数器: 程序中即将被执⾏的下⼀条指令的地址。内存指针: 包括程序代码和进程相关数据的指针还有和其他进程共享的内存块的指针。上下⽂数据: 进程执⾏时处理器的寄存器中的数据。I∕O状态信息: 包括显⽰的I/O请求,分配给进程的I∕O设备和被进程使⽤的⽂件列表。记账信息: 可能包括处理器时间总和使⽤的时钟数总和时间限制记账号等。查看进程进程的信息可以通过 /proc 系统⽂件夹查看⼤多数进程信息同样可以使⽤top和ps这些⽤⼾级⼯具来获取通过系统调用来获取进程标识符进程id(PID)父进程id(PPID)#includestdio.h#includesys/types.h#includeunistd.hintmain(){printf(pid: %d\n,getpid());printf(ppid: %d\n,getppid());return0;}通过系统调⽤创建进程-fork初识运⾏ man fork 认识forkfork有两个返回值⽗⼦进程代码共享数据各⾃开辟空间私有⼀份采⽤写时拷⻉#includestdio.h#includesys/types.h#includeunistd.hintmain(){intretfork();if(ret0){perror(fork);return1;}elseif(ret0){//childprintf(I am child : %d!, ret: %d\n,getpid(),ret);}else{//fatherprintf(I am father : %d!, ret: %d\n,getpid(),ret);}sleep(1);return0;}进程状态R运⾏状态running:并不意味着进程⼀定在运⾏中它表明进程要么是在运⾏中要么在运⾏队列⾥。S睡眠状态sleeping):意味着进程在等待事件完成这⾥的睡眠有时候也叫做可中断睡眠interruptible sleep。D磁盘休眠状态Disksleep有时候也叫不可中断睡眠状态uninterruptiblesleep在这个状态的进程通常会等待IO的结束。T停⽌状态stopped可以通过发送SIGSTOP信号给进程来停⽌T进程。这个被暂停的进程可以通过发送SIGCONT信号让进程继续运⾏。X死亡状态dead这个状态只是⼀个返回状态你不会在任务列表⾥看到这个状态。进程状态查看psaux /psaxj 命令a显⽰⼀个终端所有的进程包括其他⽤⼾的进程。x显⽰没有控制终端的进程例如后台运⾏的守护进程。j显⽰进程归属的进程组ID、会话ID、⽗进程ID以及与作业控制相关的信息u以⽤⼾为中⼼的格式显⽰进程信息提供进程的详细信息如⽤⼾、CPU和内存使⽤情况等Z-僵尸进程僵死状态Zombies是⼀个⽐较特殊的状态。当进程退出并且⽗进程使⽤wait()系统调⽤没有读取到⼦进程退出的返回代码时就会产⽣僵死(⼫)进程僵死进程会以终⽌状态保持在进程表中并且会⼀直在等待⽗进程读取退出状态代码。所以只要⼦进程退出⽗进程还在运⾏但⽗进程没有读取⼦进程状态⼦进程进⼊Z状态#includestdio#includestdlib.hintmian(){pid_t idfork();if(id0){perror(fork);return1;}elseif(id0){printf(parent[%d] is sleeping...\n,getpid());sleep(30);}else{printf(child[%d] is begin Z...\n,getpid());sleep(5);exit(EXIT_SUCCESS);}return0;}僵尸进程危害进程的退出状态必须被维持下去因为他要告诉关⼼它的进程⽗进程你交给我的任务我办的怎么样了。可⽗进程如果⼀直不读取那⼦进程就⼀直处于Z状态是的维护退出状态本⾝就是要⽤数据维护也属于进程基本信息所以保存在task_struct(PCB)中换句话说Z状态⼀直不退出PCB⼀直都要维护是的那⼀个⽗进程创建了很多⼦进程就是不回收是不是就会造成内存资源的浪费是的因为数据结构对象本⾝就要占⽤内存想想C中定义⼀个结构体变量对象是要在内存的某个位置进⾏开辟空间内存泄漏?是的孤儿进程父进程如果提前退出那么⼦进程后退出进⼊Z之后那该如何处理呢⽗进程先退出⼦进程就称之为“孤⼉进程”孤⼉进程被1号init进程领养当然要有init进程回收喽。#includestdio#includestdlib.h#includeunistd.hintmian(){pid_t idfork();if(id0){perror(fork);return1;}elseif(id0){printf(I am parent, pid: %d\n,getpid());sleep(3);exit(0);}else{printf(I am child, pid : %d\n,getpid());sleep(5);}return0;}进程优先级基本概念cpu资源分配的先后顺序就是指进程的优先权priority。优先权⾼的进程有优先执⾏权利。配置进程优先权对多任务环境的linux很有⽤可以改善系统性能。还可以把进程运⾏到指定的CPU上这样⼀来把不重要的进程安排到某个CPU可以⼤⼤改善系统整体性能。查看系统进程⽤ps‒l命令则会类似输出以下⼏个内容UID:代表执⾏者的⾝份PID:代表这个进程的代号PPID代表这个进程是由哪个进程发展衍⽣⽽来的亦即⽗进程的代号PRI代表这个进程可被执⾏的优先级其值越⼩越早被执⾏NI代表这个进程的nice值PRI and NIPRI也还是⽐较好理解的即进程的优先级或者通俗点说就是程序被CPU执⾏的先后顺序此值越⼩进程的优先级别越⾼那NI呢?就是我们所要说的nice值了其表⽰进程可被执⾏的优先级的修正数值PRI值越⼩越快被执⾏那么加⼊nice值后将会使得PRI变为PRI(new)PRI(old)nice这样当nice值为负值的时候那么该程序将会优先级值将变⼩即其优先级会变⾼则其越快被执⾏所以调整进程优先级在Linux下就是调整进程nice值nice其取值范围是-20⾄19⼀共40个级别PRI vs NI需要强调⼀点的是进程的nice值不是进程的优先级他们不是⼀个概念但是进程nice值会影响到进程的优先级变化。可以理解nice值是进程优先级的修正修正数据查看进程优先级的命令⽤top命令更改已存在进程的nice进⼊top后按“r”‒输⼊进程PID‒输⼊nice值竞争、独⽴、并⾏、并发竞争性:系统进程数⽬众多⽽CPU资源只有少量甚⾄1个所以进程之间是具有竞争属性的。为了⾼效完成任务更合理竞争相关资源便具有了优先级独⽴性:多进程运⾏需要独享各种资源多进程运⾏期间互不⼲扰并⾏:多个进程在多个CPU下分别同时进⾏运⾏这称之为并⾏并发:多个进程在⼀个CPU下采⽤进程切换的⽅式在⼀段时间之内让多个进程都得以推进称之为并发进程切换CPU上下⽂切换其实际含义是任务切换,或者CPU寄存器切换。当多任务内核决定运⾏另外的任务时,它保存正在运⾏任务的当前状态,也就是CPU寄存器中的全部内容。这些内容被保存在任务⾃⼰的堆栈中,⼊栈⼯作完成后就把下⼀个将要运⾏的任务的当前状况从该任务的栈中重新装⼊CPU寄存器,并开始下⼀个任务的运⾏,这⼀过程就是contextswitch。⼀个CPU拥有⼀个runqueue如果有多个CPU就要考虑进程个数的负载均衡问题优先级普通优先级100〜139我们都是普通的优先级想想nice值的取值范围可与之对应实时优先级0〜99不关⼼活动队列时间⽚还没有结束的所有进程都按照优先级放在该队列nr_active: 总共有多少个运⾏状态的进程queue[140]:⼀个元素就是⼀个进程队列相同优先级的进程按照FIFO规则进⾏排队调度,所以数组下标就是优先级从该结构中选择⼀个最合适的进程过程是怎么的呢1.从0下表开始遍历queue[140]2.找到第⼀个⾮空队列该队列必定为优先级最⾼的队列3.拿到选中队列的第⼀个进程开始运⾏调度完成遍历queue[140]时间复杂度是常数但还是太低效了bitmap[5]:⼀共140个优先级⼀共140个进程队列为了提⾼查找⾮空队列的效率就可以⽤5*32个⽐特位表⽰队列是否为空这样便可以⼤⼤提⾼查找效率过期队列过期队列和活动队列过期队列上放置的进程都是时间⽚耗尽的进程结构⼀模⼀样当活动队列上的进程都被处理完毕之后对过期队列的进程进⾏时间⽚重新计算active指针和expired指针active指针永远指向活动队列expired指针永远指向过期队列可是活动队列上的进程会越来越少过期队列上的进程会越来越多因为进程时间⽚到期时⼀直都存在的。没关系在合适的时候只要能够交换active指针和expired指针的内容就相当于有具有了⼀批新的活动进程总结在系统当中查找⼀个最合适调度的进程的时间复杂度是⼀个常数不随着进程增多⽽导致时间成本增加我们称之为进程调度O(1)算法环境变量基本概念环境变量(environmentvariables)⼀般是指在操作系统中⽤来指定操作系统运⾏环境的⼀些参数我们在编写C/C代码的时候在链接的时候从来不知道我们的所链接的动态静态库在哪⾥但是照样可以链接成功⽣成可执⾏程序原因就是有相关环境变量帮助编译器进⾏查找。环境变量通常具有某些特殊⽤途还有在系统当中通常具有全局特性常⻅环境变量PATH:指定命令的搜索路径HOME:指定⽤⼾的主⼯作⽬录(即⽤⼾登陆到Linux系统中时,默认的⽬录)SHELL:当前Shell,它的值通常是/bin/bash。查看环境变量⽅法echo$NAME//NAME:你的环境变量名称测试PATH1.创建hello.c⽂件#includestdio.hintmain(){printf(hello world!\n);return0;}2.对⽐./hello执⾏和之间hello执⾏3. 为什么有些指令可以直接执⾏不需要带路径⽽我们的⼆进制程序需要带路径才能执⾏4. 将我们的程序所在路径加⼊环境变量PATH当中,export PATH$PATH:hello程序所在路径和环境变量相关的命令1.echo:显⽰某个环境变量值2.export: 设置⼀个新的环境变量3.env: 显⽰所有环境变量4.unset: 清除环境变量5.set: 显⽰本地定义的shell变量和环境变量环境变量的组织⽅式每个程序都会收到⼀张环境表环境表是⼀个字符指针数组每个指针指向⼀个以’\0’结尾的环境字符串通过代码如何获取环境变量#includestdio.h#includestdlib.h#includeunistd.hexternchar**environ;intmain(intargc,char*argv[],char*env[]){for(inti0;environ[i];i){printf(environ[%d]-%s\n,i,environ[i]);}char*valuegetenv(PATH);if(valueNULL){return1;}printf(PATH-%s\n,value);for(inti0;env[i];i){printf(env[%d]-%s\n,i,env[i]);}for(inti0;iargc;i){printf(argv[%d],%s\n,i,argv[i]);}return0;}libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头⽂件中,所以在使⽤时要⽤extern声明。觉得我回答有用的话记得点个关注哟谢谢支持