Linux 系统编程--进程

1.冯诺依曼体系结构---存储程序

冯诺依曼的体系结构:存储器为核心,所有操作都通过内存来连接

比如写文档的时候:键盘编辑输入内容->加载到内存上->cpu处理调度->控制显示屏输出内容

2.操作系统--统筹管理计算机的软硬件资源

如何管理进程?------先描述、后组织

小常识---操作系统通过对驱动程序的管理实现对硬件资源的管理

               内存介质具有易失性、硬盘是持久化介质

  • 1-作用:

              a.通过驱动程序与硬件交互,对计算机资源进行统筹管理          

              b.给用户提供良好的操作环境

  • 2-什么是管理?

           ------先描述管理对象、再对被管理对象进行操作

  • 3-什么是系统调用?

           -----操作系统给用户提供的对计算机进行操作的接口

  • 4-什么是库函数?

          -----因为系统调用的复杂性,将部分系统调用进行组合封装,形成了库

  • 5系统调用与库函数的关系?

         -----库函数是对系统调用的封装,是上下级调用关系

3.进程概念

  • 1-什么是进程?-----进程控制块(PCB-process control block)

        -----简单来说,进程就是运行中的程序

        -----在内核中用task_struct这个结构体来形容进程,操作系统通过分配pcb对进程进行描述和管理

task_struct{
    内存指针  //程序代码和进程相关数据的指针
    程序计数器  //程序中即将被执行的下一条指令的地址
    上下文数据 //进程执行时处理器的寄存器中的数据
    标识符---pid  //与进程相关的唯一标识符,用来区别正在执行的进程和其他进程
    进程状态  //描述进程的状态,因为进程有挂起,阻塞,运行等好几个状态,
             //所以都有个标识符来记录进程的执行状态
    优先级  //如果有好几个进程正在执行,就涉及到进程被执行的先后顺序的问题,
           //这和进程优先级这个标识符有关
    IO状态信息  //包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表等
    记账信息--运行时长  //包括处理器的时间总和,记账号等等
}

            ps:可执行程序加载到内存上,CPU通过pcb调度进程

  • 2-如何查看进程?---使用ps命令
/* 通过pid查看进程 */
ps -ef | grep pid        >>>> -e 显示所有进程  -f 全格式显示
ps -aux | grep pid

eg:ls -l /proc/pid  // 查看一个进程,/proc目录下存放的是进程信息

查看进程信息:通过/proc查看

  • 3-如何查看进程标识符?

           ----通过调用函数pid_t getpid()获取调用进程的pid

4.进程创建

            --fork函数通过复制调用进程(父进程)的pcb来创建一个新的进程(子进程)

  • 1-父子进程的pcb相同,如何分辨父子进程?

             ---通过fork函数的返回值:

                 -1 “创建失败”

                  0 “子进程:返回0”

                 >0 "父进程:返回子进程的pid”

/* 通过fork()创建子进程 */
int pid = fork();
if (pid < 0) {
    // 复制出错 
    perror("fork error");
    exit(-1);
} else if (pid == 0) {
    // 子进程
} else {
    // 父进程
}
  • 2-创建子进程的意义?

           ----分摊压力、程序替换

  • 3-父子进程代码共享数据独有

          因为fork()通过复制父进程来创建一个子进程,所以父子进程具有相同的pcb,但是各自的数据不同,通过进程的虚拟地址空间映射到不同的物理内存上

5.进程状态

  • 1-什么是进程的状态?

           -----进程状态反映进程执行过程的变化,随着进程的执行和外界条件的变化而转换。

  • 2-类别:

           ---运行态(R)、TASK_RUNNING

              可中断睡眠态(S)、TASK_INTERRUPTIBLE

              不可中断睡眠态(D)、TASK_UNINTERRUPTIBLE

              停止态(T)、TASK_STOPPED

              僵死态(Z)、EXIT_ZOMBIE

不常见-- 死亡态(X)、EXIT_DEAD

              追踪态(t)、TASK_TRACED

          ---[ctrl]+c>>>中断       [ctrl]+z>>>变为停止态      kill pid>>>终止(Terminated)

          ---停止态的进程通过 kill -9 pid 强行终止

  • 3-僵尸进程

          ---处于僵死态的进程

          ---产生原因:子进程先于父进程退出,操作系统保留子进程的退出信息于pcb中返回给父进程,但并不释放子进程的资源,导致子进程退出,但资源未完全释放,处于僵死态

          ---危害:资源泄露、创建进程失败(一个进程可以创建的进程是有限个的)

          ---解决方案:操作系统返还子进程的退出信息给其父进程,但是当父进程也退出后,这个退出信息就失效成为无意义消息,因此通过kill掉父进程,释放子进程未释放的资源

          ---如何避免:进程等待--wait()

  • 4-孤儿进程

          ---产生原因:父进程先于子进程退出,子进程成为孤儿进程,运行在后台,父进程成为1号进程

  • 5-守护进程(精灵进程)

         ---特殊的孤儿进程(脱离终端,脱离shell会话,运行在后台)

6.进程优先级

  • 1-什么是进程优先级

           ---每个进程都有相应的优先级,以决定对CPU资源的分配调度

  • 2-如何查看进程优先级

           ---使用 ps -l 查看PRI/NI进程的优先级, top-> r pid

                           UID : 代表执行者的身份
                           PID : 代表这个进程的代号
                           PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
                           PRI :代表这个进程可被执行的优先级,其值越小越早被执行
                           NI :代表这个进程的nice值

           ---评判标准:根据NI的值:NI越小,优先级越高.[-20~19]总共41个评级,往高调整优先级需要root权限

                                修改NI的值: nice -n ni_val ./filename执行file文件并将NI设为val

                                                      renice -n ni_val -p pid调整pid进程的NI值为val

                                 注意:NI的值不是进程的优先级,不过nice值可以影响到进程的优先级变化

           ---场景:磁盘密集型:调整优先级并没有什么明显变化,没有必要

                         CPU密集型:对CPU资源要求较高的,适用

  • 3-为什么会有进程的优先级?

          --- 进程具有各自的性质--批处理/交互式,不同进程完成不同的功能

          --- 进程间具有竞争性,而cpu只有一个,为了完成任务,多个进程会对cpu进行抢占,因此,使用优先级解决竞争问题,保证每个进程都能被调度完成工作

          ---进程间具有独立性,各个进程运行期间互不干扰

  • 并行:多个进程在同一时刻都能运行在cpu上
  • 并发:在一段时间段里,只能有一个进程运行在cpu上,因为时间太短以至于看起来像是同时运行在cpu上

7.环境变量

  • 1-什么是环境变量env?

           ---保存设置操作系统运行环境参数的变量

  • 2-如何查看环境变量?

           ---通过指令echo $MYENV 打印变量内容到显示终端

           ---env | grep MYENV 在系统变量中查询MYENV

           ---set | grep MYENV 在普通变量中查询MYENV

           ---main函数的第三个参数char* env[],可以通过getenv(const char* name);获取环境变量值

  • 3-如何定义环境变量?

           ---定义一个临时变量:MYENV=1000 >>>注意:表达式不加空格!

           ---定义环境变量:export MYENV,用export设置的环境变量只属于1个shell终端

           ---添加一个环境变量:PATH=$PATH+当前路径,PATH为默认路径变量

  • 4-如何移除环境变量?

           ----移除指定环境变量:unset MYENV

  • 5-常见的环境变量

           --- HOME、SHELL、PATH

  • 6-环境变量的全局特性--继承特性

          ---每一个shell终端都有自己独立的环境变量,shell的子终端也具备其父终端的环境变量

          ---shell上执行的可执行程序继承了该终端的环境变量,让子程序执行命令,规避风险,峰值shell崩溃

  • 7-shell原理

          ---将命令行的字符串解析成操作系统的库命令--对系统调用接口的封装

          ---程序替换:获取字符串>>解析字符串>>fork()>>子进程进行程序替换

  • 8-环境变量的设置位于/etc/profile文件

8.程序地址空间--代码共享、数据独有

                                                        

  • 1-什么是虚拟地址空间?

          虚拟地址空间---pcb中的mm_struct,是操作系统为进程所描述的一段空间

struct mm_struct{
    unsigned long size;
    unsigned long code_start;
    unsigned long code_end;
    unsigned long data_start;
    unsigned long data_end;
}
  • 2-为什么要使用虚拟地址空间,而不直接给物理内存?

                                                  

物理内存采用分页式内存管理,实行碎片化管理;

虚拟地址空间采用页式内存管理,通过虚拟页号从页表中的映射关系找到对应的物理页号,根据页表中的内存控制单元MMU获取内存的访问方式,最后根据页内偏移得到实际地址,进行访问

           虚拟地址空间内,进程所占用的连续内存段通过页表映射关系映射到物理内存上,因为物理内存的碎片化管理,可以充分利用物理内存,提高内存利用率。而如果实际访问物理内存,给变量直接分配物理内存,可能会因为缺乏访问控制,而造成内存的非法访问,导致程序崩溃。

           虚拟地址空间 + 页表 : a.提高内存利用率;        b.对内存访问进行控制

  • 3-父子进程中打印同一个变量的值和地址,值不一样,地址却完全相同???
int val = 100;
pid_t pid = fork();
if (pid < 0) {
    // 出错
    perror("fork error");
    return -1;
} else if (pid == 0) {
    //子进程
    val = 50;
    printf("%d: %d--%p\n", getpid(), val, &val);
} else {
    //父进程
    printf("%d: %d--%p", getpid(), val, &val);
}

           共享:代码通过虚拟地址空间,在页表上映射到相同的物理内存

           独有:数据通过虚拟地址空间,在页表上映射到不同的物理内存

  ---实际上相同的是虚拟地址空间里的地址,而不是物理内存上的地址

           写时拷贝:为了保证进程间的独立性,在子进程的数据需要进行运算的时候,操作系统通过页表的映射关系为子进程的数据会在物理内存上重新开辟一段空间,然后更新页表信息,然后将其拷贝返还给子进程。减少子进程的PCB复制开销

           父子进程具有各自的pcb,虽然子进程pcb是因为复制父进程的pcb,它们的代码映射到相同的物理内存,但是数据却可能被映射到不同的物理内存上。这就是虽然父子进程的变量地址打印结果相同,值却不同的原因。实现了父子进程之间代码共享,数据独有。

9.进程调度--进程的O(1)调度算法

  • 1-优先级调度算法--结合先进先出

     -----操作系统使用队列管理pcb,采用先进先出算法进行调度进程。但是因为进程具有优先级,每一次调度都需要遍历这个队列,查找最高的优先级然后对其调度,因此使用包含了140个队列的队列数组-----quene_array,每个元素分别对应140个优先级,同一个优先级内,按照先进先出算法调度。 这140个队列就称为优先级队列。

     -----虽然使用队列数组quene_array管理pcb,但每一次调度都需要根据优先级进行140个元素的遍历访问,所以操作系统使用一个二进制位图来标识优先级队列里是否包含运行的队列,当前队列里包含pcb,对应的二进制位图就置1

     -----为了提高调度的效率,操作系统使用两个队列数组active_quene_array(需要调度的队列),expired_quene_array(已经调度结束的队列)进行调度pcb,从active中获取就绪状态的pcb,分配资源,调度结束后放置在expired中。

  • 3-SJF-短作业优先调度算法

     -----短作业优先(SJF)调度算法是从后备队列中选择一个或若干个估计运行时间最短的作业,将它们调入内存运行。而短进程优先(SPF)调度算法,则是从就绪队列中选择一个估计运行时间最短的进程,将处理机分配给它,使之立即执行,直到完成或发生某事件而阻塞时,才释放处理机。

  • 4-时间片轮转调度算法

     -----时间片轮转调度算法主要适用于分时系统。在这种算法中,系统将所有就绪进程按到达时间的先后次序排成一个队列,进程调度程序总是选择就绪队列中第一个进程执行,即先来先服务的原则,但仅能运行一个时间片,如100ms。在使用完一个时间片后,即使进程并未完成其运行,它也必须释放出(被剥夺)处理机给下一个就绪的进程,而被剥夺的进程返回到就绪队列的末尾重新排队,等候再次运行。

     ----在时间片轮转调度算法中,时间片的大小对系统性能的影响很大。如果时间片足够大,以至于所有进程都能在一个时间片内执行完毕,则时间片轮转调度算法就退化为先来先服务调度算法。如果时间片很小,那么处理机将在进程间过于频繁切换,使处理机的开销增大,而真正用于运行用户进程的时间将减少。因此时间片的大小应选择适当。

  • 5-高响应比优先调度算法

     ----高响应比优先调度算法主要用于作业调度,该算法是对FCFS调度算法和SJF调度算法的一种综合平衡,同时考虑每个作业的等待时间和估计的运行时间。在每次进行作业调度时,先计算后备作业队列中每个作业的响应比,从中选出响应比最高的作业投入运行。
     ----响应比的变化规律可描述为:

     根据公式可知:

          当作业的等待时间相同时,则要求服务时间越短,其响应比越高,有利于短作业。

          当要求服务时间相同时,作业的响应比由其等待时间决定,等待时间越长,其响应比越高,因而它实现的是先来先服务。

          对于长作业,作业的响应比可以随等待时间的增加而提高,当其等待时间足够长时,其响应比便可升到很高,从而也可

   获得处理机。克服了饥饿状态,兼顾了长作业。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值