zoukankan      html  css  js  c++  java
  • Linux课程学习总结

    Linux系统概念模型

    linux操作系统是一个基于POSIX的多用户、多任务、支持多线程的复杂系统。它的复杂程度难以想象,作为一个操作系统linux为用户提供进程管理、内存管理、设备控制以及网络管理等功能。
    Linux系统一般有4个主要部分:内核、shell、文件系统和应用程序。内核、shell和文件系统一起形成了基本的操作系统结构,它们使得用户可以运行程序、管理文件并使用系统。
    linux主要结构如下

    中断

    中断是指 CPU 对系统发生某事件时的这样一种响应。CPU 暂停正在执行的程序,在保留现场后自动地转去执行该事件的中断处理程序,执行完后,再返回到原程序的断点处继续执行。

    不管是外部中断还是内部中断,在它们到达CPU之前,都会首先经过一个叫做中断控制器(Interrupt Controller)的硬件,其作用是根据中断源(Interrupt Source,也叫IRQ - Interrupt Request)的优先级对中断进行派发。Linux中描述中断控制器的数据结构是struct irq_chip,因为不同芯片的中断控制器对其挂接的IRQ有不同的控制方法,因而这个结构体主要是由一组用于回调(callback),指向系统实际的中断控制器所使用的控制方法的函数指针构成。
    irq_chip部分结构如下:

    struct irq_chip {
    	const char    *name;
    	void	     (*irq_enable)(struct irq_data *data);
    	void	     (*irq_disable)(struct irq_data *data);
    	void	     (*irq_mask)(struct irq_data *data);
    	void	     (*irq_unmask)(struct irq_data *data);
    
    	void	     (*ipi_send_single)(struct irq_data *data, unsigned int cpu);
    	void	     (*ipi_send_mask)(struct irq_data *data, const struct cpumask *dest);
    	...
    };
    
    • "irq_enable/irq_unmask"用于中断使能,"irq_disable/irq_mask"用于中断屏蔽。在多核系统中,CPU之间的中断被称为IPI(Inter-Processor Interrupt),因此"ipi_send_single"表示这个IPI是发给单独的一个CPU,ipi_send_mask"表示IPI是发给mask范围内是所有CPU。
    • "irq_desc"中的"action"是IRQ对应的中断处理函数(ISR - Interrupt Service Routine),按理ISR应该就是一个函数指针,可这里确是一个指向struct irqaction的指针。
    • 当一个中断发生的时候,其对应IRQ链表上的所有"irqaction"的"handler"都将被依次执行,以判断是否是自己的设备产生的中断,这主要靠读取自己设备的中断状态寄存器来完成。因此共享中断时,即便不是你的设备产生的中断,"handler"也会被调用到。为了避免无谓的消耗,需要一进"handler"就立刻进行判断,如果不是,就尽快的退出。

    进程管理

    进程主要由以下几部分组成:

    代码段:编译后形成的一些指令
    数据段:程序运行时需要的数据
    只读数据段:常量
    已初始化数据段:全局变量,静态变量
    未初始化数据段(bss):未初始化的全局变量和静态变量
    堆栈段:程序运行时动态分配的一些内存
    PCB:进程信息,状态标识等
    Linux内核中进程用task_struct结构体表示,称为进程描述符,该结构体相对比较复杂,有几百行代码,记载着该进程相关的所有信息,比如进程地址空间,进程状态,打开的文件等。对内核而言,进程或者线程都称为任务task。内核将所有进程放入一个双向循环链表结构的任务列表(task list)

    进程状态

    进程结构体task_struct有一个成员state,代表的是进程的状态。 进程所有可能的状态定义在文件kernel/include/linux/sched.h, 下面是linux的进程状态转换图:

    进程调度

    进程调度控制进程对CPU的访问。进程调度的时候需要进入内核态,并切换虚拟地址空间,切换内核栈和硬件上下文,容易造成cache失效、页表切换等问题。进程的频繁切换容易造成资源浪费,开销很大。Linux使用了比较简单的基于优先级的进程调度算法选择新的进程。内核通过schedule函数实现进程调度,schedule函数负责在运行队列中选择一个进程,然后把它切换到CPU上执行。linux调度策略是模块化设计的,调度器根据不同的进程依次遍历不同的调度策略,找到进程对应的调度策略,调度的结果即为选出一个可运行的进程指针,并将其加入到进程可运行队列中。调度器的工作流程如下图

    文件系统

    Linux是采用虚拟文件系统(VFS),屏蔽了底层具体使用的文件系统(minix,Ext2...,FAT,device,etc),对上层用户进程提供了统一的操作接口,如read,write,open,close系统调用。VFS是一种通用文件模型,包含两个接口,一个与用户连接,一个与底层的文件系统层(提供具体的文件结构实现)连接。不同文件系统通过mount(挂载、安装)到根文件系统中。用户通过VFS提供的read(),write()等系统调用操作文件,VFS调用sys_read()、sys_write()。

    读写文件举例

    读文件流程

    • 进程调用库函数向内核发起读文件请求;

    • 内核通过检查进程的文件描述符定位到虚拟文件系统的已打开文件列表表项;

    • 调用该文件可用的系统调用函数read()

    • read()函数通过文件表项链接到目录项模块,根据传入的文件路径,在目录项模块中检索,找到该文件的inode;

    • 在inode中,通过文件内容偏移量计算出要读取的页;

    • 通过inode找到文件对应的address_space;

    • 在address_space中访问该文件的页缓存树,查找对应的页缓存结点:

      (1)如果页缓存命中,那么直接返回文件内容;
      (2)如果页缓存缺失,那么产生一个页缺失异常,创建一个页缓存页,同时通过inode找到文件该页的磁盘地址,读取相应的页填充该缓存页;重新进行第6步查找页缓存;

    • 文件内容读取成功。

    写文件流程

    • 进程调用库函数向内核发起读文件请求;

    • 内核通过检查进程的文件描述符定位到虚拟文件系统的已打开文件列表表项;

    • 调用该文件可用的系统调用函数write()

    • write()函数通过文件表项链接到目录项模块,根据传入的文件路径,在目录项模块中检索,找到该文件的inode;

    • 在inode中,通过文件内容偏移量计算出要读取的页;

    • 通过inode找到文件对应的address_space;

    • 在address_space中查询对应页的页缓存是否存在,如果页缓存命中,直接把文件内容修改更新在页缓存的页中。写文件就结束了。这时候文件修改位于页缓存,并没有写回到磁盘文件中去。

    • 如果页缓存缺失,那么产生一个页缺失异常,创建一个页缓存页,同时通过inode找到文件该页的磁盘地址,读取相应的页填充该缓存页。此时缓存页命中,进行第6步。

    • 一个页缓存中的页如果被修改,那么会被标记成脏页。脏页需要写回到磁盘中的文件块。有两种方式可以把脏页写回磁盘:

      (1)手动调用sync()或者fsync()系统调用把脏页写回
      (2)pdflush进程会定时把脏页写回到磁盘

    影响程序执行性能的因素

    • 磁盘 I/O
      磁盘的读写速度远慢于内存的读写速度,系统运行是如果需要等待磁盘I/O的完成,将导致整个系统的性能下降;

    • CPU性能
      应用对CPU的占用时间不同,应用间对CPU的抢占也将导致系统性能受到影响;
      可以使用perf top 可实时显示占用 CPU 时钟最多的函数或指令,可对热点函数进行针对性优化

    • 内存
      ​ 内存的大小也是影响 Linux 性能的一个重要的因素。内存太小,系统进程将被阻塞,应用也将变得缓慢,甚至失去响应;内存太大,会导致资源浪费。

    • 网络状态
      ​ 网络带宽也是影响性能的一个重要因素,低速的、不稳定的网络将导致网络应用程序的访问阻塞;而稳定、 高速的带宽,可以保证应用程序在网络上畅通无阻地运行

    • 软件因素
      程序自身的算法以及所使用的数据结构、应用程序的链接方式等等都会对程序的运行效率造成影响

    应用程序实例

    简单写一个遍历程序,并使用perf进行分析

     int main(){
         char a[1000][1000];
         for(int i=0; i < 1000;i++){
             for(int j=0; j < 1000;j++){
              a[i][j] = 'b';
             }
         }
         return 0;
      }
    

    使用perf命令对程序进行分析

    分析结果主要参数:
    task‐clock是表示目标任务真正占用处理器的时间,单位是毫秒。也称任务执行时间
    context-switches是系统发生上下文切换的次数
    CPU-migrations是任务从一个处理器迁往另外一个处理器的次数
    page-faults是内核发生缺页的次数

    总结

    经过这学期的linux课程的学习,让我对linux操作系统有了更加深入的认识,而不是向以前那样只是熟悉几个操作命令。这里感谢孟老师以及李老师的辛苦付出,通过几次操作性强的实验课让我们从简单到复杂,从表面到深入地理解了linux内部运行过程,受益匪浅。

  • 相关阅读:
    编译器是C写的,包括一点C++,editor和debugger是C++写的(最早的16位编译器是纯汇编写的)
    2016 年美国大选,特朗普赢在哪儿?
    特朗普上台的原因:是经济全球化被甩出去人的反扑。但互联网时代不可阻挡,必须参与。开历史倒车是没用的,就像欧洲的羊吃人时代是一样的。信仰基督教以及美国传统价值观的那群老人,终归是要死去。
    Java 开发规约插件
    c#.net公共帮助类
    elasticsearch集群及filebeat server和logstash server
    NopCommerce源码架构
    局部函数
    C#实现人脸识别
    NET Core
  • 原文地址:https://www.cnblogs.com/--CYH--/p/14777750.html
Copyright © 2011-2022 走看看