背景:
Linux中./a.out windows的双击、手机打开app 这些都叫做进程
如何把这些加载到内存当中的程序进行管理?
操作系统如何管理进程呢?先描述,再组织
概念:
什么叫进程?加载到进程内的代码和数据和该进程在内核当中的创建的pcb数据结构,两个合起来才叫进程。
对于进程做任何管理,就进而转化成了对于进程对应的pcb(process control block)结构体形成的链表进行增删查改。
为什么要有pcb?Linux下是tsak_struct
因为进程需要被管理,管理的思路是先描述再组织,为了更好的描述,所以需要PCB。
可执行程序加载到内存了,可执行程序不是有代码和数据嘛,对应的是文件的内容还是属性?
是内容
进程的属性和磁盘文件中的属性,它们两个有关系吗?
有关系,但关系不大。
命令行查看进程的两种方式
方式一:
ps axj 查看系统所有进程
ps axj | grep process process为正在运行进程的名字
ps axj | head -1 显示进程的属性名
ps axj | head -1 && ps axj | grep process process为正在运行进程的名字
如下图
或者ps axj | head -1 && ps axj | grep PID PID为正在运行进程的ID
如下图
方式二:ls /proc
上上图的PPID是什么呢?——父进程ID
那么,如何获取进程id呢?——通过函数接口getpid()和getppid()
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
printf("pid: %d\n", getpid());
printf("ppid: %d\n", getppid());
return 0;
}
注意看下图的bash,可知:
1.bash命令行解释器,本质上也是一个进程;
2.命令行启动的所有的程序,最终都会变成进程,而该进程对应的父进程都是bash(如何做到后面说)
如何杀掉进程?——命令行输入 kill -9 7701 7701为对应进程的PID
那么可以杀掉bash吗?——当然可以,只不过系统会崩溃,重新登陆就行。
fork的使用
如何在代码层面中创建子进程?——调用fork函数
fork的返回值:失败返回-1,给子进程返回0,给父进程返回子进程的pid。那么为什么呢?
(感性的认识)。
理论上:父进程:子进程=1:n、
进程的使用:
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
int main()
{
int x=10;
pid_t ret=fork();
if(ret<0)
{
perror("fork fail");
exit(-1);
}
else if(ret>0)
{
//父进程
while(1)
{
printf("我是父进程,我的pid是:%d,我的父进程是:%d,x=%d,&x=%p\n",getpid(),getppid(),x, &x);
sleep(1);
}
}
else //ret==0
{
//子进程
while(1)
{
printf("我是子进程,我的pid是:%d,我的父进程是:%d,x=%d,&x=%p\n",getpid(),getppid(),++ x,&x);
sleep(1);
}
}
return 0;
}
fork之后,父进程和子进程哪个先运行由调度器决定。
为什么fork有两个返回值?
if 和else if 同时成立了;两个while循环同时运行了。
因为fork之后,有了两个执行流;
fork之后,所有的代码(包括fork前)共享,通常通过if和else if 来进行执行流分流
为什么&ret一样?
fork原理
fork做了什么?
进程=内核数据结构+进程的代码和数据
子进程pcb会拷贝大部分父进程的内容
创建子进程,因为子进程没有自己独立的代码和数据,默认创建子进程会共享父进程的代码和数据。
fork如何看待代码和数据?
代码是只读的,当有一个执行流尝试修改数据时,OS会自动给我们当前进程触发:
写时拷贝
进程在运行的时候是有独立性的。(终止qq不影响微信),如何做到的?后面学
父子进程,运行时也是一样的。
fork如何理解两个返回值?
当我准备在函数内部执行return时,这个函数的主体功能是否已经跑完?
return的时候,函数主体功能已经完成,fork是一个函数,fork函数的return也是一个语句,return也被执行了2次,只不过看不见罢了。返回两次,并不意味着会保存两次。
这个地址不是物理地址,而是虚拟地址。
只要想到进程,优先想到进程对应的task_struct。
LinuxOS进程的状态
新建:即字面意思
运行:task_struct结构体在运行队列中排队,就叫做运行态
阻塞:等待非cpu资源就绪,阻塞状态
挂起:当内存不足时,OS通过适当的置换进程的代码和数据到磁盘,此时进程的状态就叫做挂起。
kill -19 15334 暂停进程
kill -18 15334 继续进程
僵尸进程的危害:内存泄漏
孤儿进程:
一般回收子进程,都是父进程来做。
父进程退出,子进程还在,子进程叫做孤儿进程。
孤儿进程会被领养,被1号进程领养(init,系统本身)。
为什么要被领养?
未来当子进程退出的时候,父进程早已不在,需要领养进程来进行回收。
进程优先级
为什么要有优先级?就是因为CPU是有限的,而进程太多,需要通过某种方式竞争资源!
什么是优先级?确实是谁应该先获得某种资源,谁后获得(我们可以用一些数据表明优先级的)
Linux具体的优先级做法:
优先级=老的优先级+nice值 老的优先级,都是80,每次设置优先级,都要从进程最开始的优先级开始设置
PRI:优先级,越小就越早被执行 NI:NICE值,修正(下图),NICE值范围-20~19
ps -la 查看进程
如图:
更改优先级,本质是更改nice值:top命令->r命令->输入pid->输入新的nice值
系统不让我们把优先级往高了调,怎么办?sudo top
补充概念:
竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高
效完成任务,更合理竞争相关资源,便具有了优先级。
独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。
并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行。
并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称为并发
抢占与出让:更高优先级的进程到来之时而抢占正在CPU上跑的低优先级进程
并行是真正有两个CPU
并发是在一个CPU下,多个进程在一个时间段内,代码都得以推进
切换: