《Linux系统编程之系统导论》【冯诺依曼体系结构 + 操作系统基本概述】

【冯诺依曼体系结构 + 操作系统基本概述】目录

  • 前言:
  • ---------------冯诺依曼体系结构---------------
    • [1. 什么是冯诺依曼体系结构?](#1. 什么是冯诺依曼体系结构?)
    • [2. 程序在运行之前为什么要加载到内存中?](#2. 程序在运行之前为什么要加载到内存中?)
    • [3. 冯诺依曼体系结构的局限?](#3. 冯诺依曼体系结构的局限?)
    • [4. 如何通过冯诺依曼体系结构来理解数据流动?](#4. 如何通过冯诺依曼体系结构来理解数据流动?)
  • ---------------操作系统概述---------------
    • [1. 什么是操作系统?](#1. 什么是操作系统?)
    • [2. 操作系统有哪些部分组成?](#2. 操作系统有哪些部分组成?)
    • [3. 为什么需要操作系统?](#3. 为什么需要操作系统?)
    • [4. 操作系统是如何进行管理的?](#4. 操作系统是如何进行管理的?)
    • [5. 什么是系统调用和库函数?](#5. 什么是系统调用和库函数?)

往期《Linux系统编程》回顾:

/------------ 入门基础 ------------/
【Linux的前世今生】
【Linux的环境搭建】
【Linux基础 理论+命令】(上)
【Linux基础 理论+命令】(下)
【权限管理】

/------------ 开发工具 ------------/
【软件包管理器 + 代码编辑器】
【编译器 + 自动化构建器】
【版本控制器 + 调试器】
【实战:倒计时 + 进度条】

前言:

🎉hi~ 小伙伴们大家光棍节好啊,☆(・ω<)★✨

嗯~ o( ̄▽ ̄)o今天是双11哦,一个兼具 "单身社交" 与 "消费狂欢" 双重属性的节日,影响力覆盖全年龄段,太有氛围感啦~哈哈 (ノ≧∀≦)ノ💻🛒
经过之前的铺垫,咱们已经能熟练操作 Linux 操作系统,也摸清了 Linux 下的常用开发工具,还通过实战练了手 ------ 现在,终于要正式踏入《Linux 系统编程》的核心学习啦!

在开启正题前,先给大家安排一份 "新手必看先导教程"------【冯诺依曼体系结构 + 操作系统基本概述】

这俩内容是理解系统编程的 "底层逻辑钥匙",咱们简单说说重点:≧◉◡◉≦💡

  • 冯诺依曼体系结构:是现代计算机的设计基础,明确了计算机五大核心部件组成,还规定了数据和指令的存储与运行方式,搞懂它就能明白程序在电脑里是怎么 "跑起来" 的 (・∀・)ノ゙
  • 操作系统基本概述:则会带大家认识 "系统管家" 的核心作用 ------ 它是硬件和应用软件之间的桥梁,负责管理硬件资源、调度程序运行、提供用户交互接口,咱们平时用 Linux 的各种操作,背后都是操作系统在默默 "打工"~ (`・ω・´)

先把这两个基础知识点吃透,后续学习系统编程就能事半功倍,赶紧跟着鼠鼠一起解锁这份 "入门秘籍" 吧! (´。• ᵕ •。)

---------------冯诺依曼体系结构---------------

1. 什么是冯诺依曼体系结构?

冯・诺依曼体系结构 :是 1945 年由美籍匈牙利数学家约翰・冯・诺依曼(John von Neumann)提出的 计算机硬件设计框架

  • 它确立了现代计算机的核心结构逻辑,至今仍是绝大多数通用计算机(如:个人电脑、服务器)的设计基础
  • 其核心是 "存储程序原理",即 "程序与数据以二进制形式共同存储在存储器中,计算机按顺序读取指令并执行",具体包含五大核心组件和三大基本特征

五大核心硬件组件

  1. 运算器(Arithmetic Logic Unit, ALU)
    负责执行算术运算(如:加减乘除)和逻辑运算(如:与、或、非、比较),是计算机的 "计算核心"
  2. 控制器(Control Unit, CU)
    负责协调计算机各组件的工作:按顺序从存储器中读取指令解析指令含义再向运算器、存储器、输入/输出 设备发送控制信号,确保指令逐步执行(相当于计算机的 "指挥中心")
  3. 存储器(Memory)
    用于 同时存储程序代码和数据 (冯・诺依曼的核心设计之一),早期以磁芯存储器为主,现代则以内存(RAM)为代表。特点是 "按地址访问",即通过地址找到对应的存储单元,读取或写入二进制信息
  4. 输入设备(Input Device)
    负责将外部信息(如:用户操作、数据文件)传入计算机
    • 例如:键盘、鼠标、话筒、摄像头、扫描仪、网卡、磁盘
  5. 输出设备(Output Device)
    负责将计算机的处理结果反馈到外部
    • 例如:显示器、打印机、音箱、网卡、磁盘

关于冯・诺依曼体系结构,有几点关键内容需要强调:

  • 这里所提及的存储器,指的是内存
  • 在不考虑缓存的情况下,CPU 仅能对内存进行读写操作,无法直接对输入或输出设备等外设进行数据层面的访问
  • 外设(输入或输出设备)若要进行数据的输入或输出,也只能向内存写入数据或者从内存中读取数据

简而言之 :所有设备都只能直接与内存进行数据交互


三大核心特征

  1. 程序与数据同源存储
    程序(指令序列)和数据都以二进制形式存储在同一个存储器中,而非分开存储(区别于早期 "程序外存" 的设计),这让计算机可以灵活加载不同程序,实现通用计算
  2. 指令执行的 "串行顺序性"
    控制器按 "取指令→解析指令→执行指令→取下一条指令" 的顺序循环执行(称为 "指令周期"),默认情况下指令逐条串行处理(现代计算机通过多核、流水线等技术优化,但核心逻辑仍基于此)
  3. 二进制编码
    计算机内部所有信息(指令、数据、符号等)均以二进制(0 和 1)表示,这是因为电子元件(如:晶体管)的 "通/断" 状态天然适合二进制逻辑,便于硬件实现和信号传输

2. 程序在运行之前为什么要加载到内存中?

在冯・诺依曼体系结构下,软件运行有着明确的流程和规则:

软件(程序)在运行之前,是以文件形式存储在磁盘 等外存储设备中的。而要让程序运行起来,必须先将其从磁盘加载到内存中。

这一要求是由冯・诺依曼体系结构规定的,因为该体系结构下,CPU 无法直接从磁盘等外设获取程序指令和数据来执行。


1. CPU 与内存的交互核心:CPU 要获取指令、写入数据,都只能与内存进行交互

  • 也就是说,CPU 执行我们编写的代码、访问程序中使用的数据时,这些代码和数据必须事先存在于内存里

2. 外设与内存的协作

  • 当涉及到输入(Input)操作时,外部设备(如:键盘、鼠标、传感器等)不能直接将数据传递给 CPU,而是需要先把数据 "拷贝" 到内存
  • 同样,输出操作时,数据也是从内存 "拷贝" 到外部输出设备(如:显示器、打印机等)

整体来看,数据在设备间的流转,是从一个设备 "拷贝" 到另一个设备的过程

3. 冯诺依曼体系结构的局限?

冯・诺依曼体系的核心瓶颈是 "冯・诺依曼瓶颈"
由于存储器与运算器之间的数据传输速度,远低于运算器的处理速度,导致计算机整体性能受限于 "数据传输带宽"


所以冯・诺依曼体系结构的整体效率,很大程度上 由设备之间 "拷贝" 数据的效率决定

  • 因为数据在不同设备(如:磁盘到内存、内存到 CPU、内存到其他外设等)之间的传输速度,会直接影响程序执行的整体速度
  • 如果 "拷贝" 效率低下,即便 CPU 运算能力很强,整个系统的运行也会受到制约,就像是木桶原理 ------ 木桶能装多少水,取决于最短的那块木板。哪怕 CPU 运算速度再快(如同木桶中较长的木板),但只要数据在内存、外设、CPU 之间的传输("拷贝")拖慢了节奏,整个系统的性能就会被这一环节限制,无法充分发挥 CPU 等高速组件的能力

为缓解这一问题,现代计算机在其基础上增加了缓存(Cache)多核处理器并行计算架构等,但核心的 "存储程序 + 五大组件" 逻辑仍未改变,因此仍属于冯・诺依曼体系的延伸。

4. 如何通过冯诺依曼体系结构来理解数据流动?

要深入理解冯・诺依曼体系结构,不能仅停留在概念层面,而要结合实际软件的数据流动过程来分析。

以在 QQ 上和朋友聊天(发送消息)为例,详细解释数据的流动过程:


发送消息的数据流过程(以北京用户给南京用户发 "你好!" 为例)

  • 输入阶段:消息录入与初步处理

    • 用户在位于北京的电脑上,通过键盘输入 "你好!",此时,键盘作为输入设备,将用户的按键操作转化为电信号形式的数据,然后把这些数据传输到计算机的内存中(遵循冯・诺依曼体系 "数据需先进入内存" 的规则)
    • 同时,QQ 软件本身也早已被加载到内存中运行,随时准备处理用户的输入操作
  • 处理与传输阶段:数据的运算、封装与网络发送

    • 计算机的 中央处理器(CPU) 从内存中读取 QQ 程序的指令以及刚输入的 "你好!" 消息数据,进行一系列运算和处理(比如:按照 QQ 程序的逻辑,对消息进行格式封装等)
    • 处理完成后,CPU 控制将封装好的消息数据再次写入内存
    • 接着,网卡作为输出设备(负责网络数据输出),从内存中读取这些消息数据,按照网络通信协议(如:TCP/IP)进一步封装成网络数据包,然后通过网络(如:互联网)发送出去,数据包会经过一系列网络设备中转,最终向南京方向传输
  • 接收与显示阶段:数据的接收、解析与呈现

    • 首先,位于南京的电脑的网卡作为输入设备,接收到来自网络的数据包后,将其传输到内存中
    • 然后,CPU 从内存中读取数据包,按照 QQ 程序的逻辑进行解析,提取出 "你好!" 这条消息数据
    • 最后,显示器作为输出设备,从内存中获取解析后的消息数据,将 "你好!" 显示在屏幕上,完成整个消息接收与展示的过程

---------------操作系统概述---------------

1. 什么是操作系统?

操作系统(Operating System,简称 OS) :是 管理计算机硬件软件资源的核心系统软件 ,也是计算机系统中所有其他软件运行的 "基础平台""桥梁"

  • 它介于计算机硬件(如:CPU、内存、磁盘)和用户(或应用程序,如:QQ、浏览器、Office)之间
  • 它负责 协调硬件资源分配、管理软件运行逻辑,同时为用户提供便捷的交互接口,是计算机能够正常工作的 "灵魂",没有操作系统,你的电脑就是一堆行尸走肉的废铁

2. 操作系统有哪些部分组成?

概括来讲,操作系统主要由以下两部分组成:

  • 内核 :它承担着核心的管理工作,具体包括:
    • 进程管理(负责调度管理计算机中运行的程序进程)
    • 内存管理(对计算机的内存资源进行分配回收等操作)
    • 文件管理管理存储设备上的文件,如:创建、删除、读写文件等)
    • 驱动管理(为计算机硬件设备提供驱动支持,使硬件能与系统正常交互)
  • 其他程序
    • 函数库(为应用程序提供可调用的函数,助力程序实现各类功能)
    • shell 程序(为用户提供与操作系统内核交互的命令行界面,方便用户输入指令操作计算机)

3. 为什么需要操作系统?

如果没有操作系统,用户要使用计算机必须 "直接与硬件对话"------ 比如:用二进制代码编写指令控制 CPU,手动管理内存地址,这对普通人来说几乎不可能。

操作系统相当于"管家":

  • 对用户:提供简单的交互方式(点击图标、输入指令),无需了解硬件细节
  • 对应用程序:提供统一的接口,让软件无需适配不同硬件(比如:QQ 无需区分 "Intel CPU" 还是 "AMD CPU",只需调用操作系统的接口即可)
  • 对硬件:合理分配资源,避免浪费(比如:CPU 不会因 "只运行一个小程序" 而闲置,内存不会因 "多个程序混乱占用" 而崩溃)

简单来说:操作系统就像计算机的 "管家":

  • 既要,管好家里的 "硬件家具"(CPU、内存等)
  • 又要,服务好 "软件客人"(应用程序)
  • 还要,让 "主人"(用户)用得省心

没有它,计算机就是一堆无法协同工作的硬件零件。

小故事:国家的政府

一个生动的比喻: 操作系统就像是国家的政府

  • 硬件(CPU、内存、硬盘)就像是国家的资源 (土地、矿产、人力)
  • 应用程序(微信、Chrome浏览器、游戏)就像是国家的公司、学校、医院

政府做什么?

  1. 管理资源:政府决定土地给谁用,资金如何分配
  2. 提供公共服务:政府修建公路、提供电力、制定法律
  3. 协调与仲裁:如果两个公司争夺同一块地,政府来协调

没有政府,国家会陷入混乱;没有操作系统,计算机就无法工作

说白了操作系统就是一个:"管理者" 与 "协调者"

4. 操作系统是如何进行管理的?

一、"管理" 的核心逻辑(以 "校长管理学生" 类比)

要理解操作系统的 "管理",可以先看生活中的例子:校长(管理者)管理学生(被管理者),而辅导员负责执行校长的决策。

操作系统的 "管理" 也遵循类似逻辑,且有三个关键特点:

  • 管理者与被管理者可 "不直接见面"

    • 校长不需要逐个找学生沟通,就能完成管理
    • 类似地,操作系统管理硬件、程序等 "被管对象" 时,也无需和它们 "直接交互"
  • "数据" 是管理的核心依据

    • 校长如何了解学生情况?靠 "Excel 表格" 里的学生数据(姓名、年龄、成绩等)
    • 操作系统管理计算机资源(如:进程、内存、文件)时,也是通过 "数据结构" 记录资源的状态、属性,以此为依据做决策
  • "中间层" 负责数据传递

    • 校长不直接找学生要数据,而是由辅导员收集后汇报
    • 操作系统里,硬件的状态、程序的信息也会通过 "驱动程序"、"系统接口" 等中间层,传递给操作系统的 "管理模块"

二、操作系统 "管理" 的技术映射:从 "Excel 表格" 到 "数据结构与算法"

生活中校长用 "Excel 表格" 管理学生,操作系统则用 "数据结构 + 算法" 实现对计算机资源的管理

以 "管理学生" 类比 "管理进程(运行的程序)" 为例:

  • "描述" 被管对象

    • 校长在 Excel 里用 "列" 定义学生的属性(姓名、年龄、成绩)
    • 操作系统会用 结构体(如:struct stu) 定义进程的属性(进程 ID、内存占用、运行状态等)
    c 复制代码
    struct stu 
    {
        char name[20];   // 姓名
        int age;         // 年龄
        float score;     // 成绩
    
        // 其他属性...
        struct stu *next; // 链表指针,用于组织多个学生
    };
  • "组织" 被管对象

    • 校长把学生的 Excel 行按 "班级"、"学号" 组织起来
    • 操作系统会用 数据结构(如:链表、数组) 把进程的结构体 "串起来",形成 "进程链表"(如:stu list),方便批量管理(新增、删除、查询进程)
  • "操作" 被管对象

    • 校长对 Excel 里的学生数据做 "增删查改"
    • 操作系统会用**算法**对进程链表执行同样的操作(比如:新增一个进程时,把它的结构体插入链表;查询进程时,遍历链表找对应结构体)

三、"先描述,再组织":操作系统的通用管理思路

无论是管理进程、内存,还是文件,操作系统都遵循 "先描述,再组织" 的逻辑:

  1. 先描述:用 "结构体" 等方式,把被管对象的核心属性 "描述" 清楚(如:进程的 ID;内存占用;文件的路径、大小、权限)
  2. 再组织:用 "链表"、"哈希表" 等数据结构,把这些 "描述好的对象" 组织起来,形成可高效操作的 "资源集合"

这种思路能对任何 "管理场景" 进行建模(小到管理进程,大到管理分布式系统资源)


大家可以回想一下:很多面向对象编程语言中,是不是都有 "类" 和 "容器" 这两个核心概念?

只是不同语言的命名或具体实现略有差异 ------ 比如:

  • C++ 里的容器归属于 STL(标准模板库)
  • Java 中的容器是 Collections 框架 (如:ArrayListHashMap 等)
  • Python 里则直接提供了 内置容器类型 (如:列表 list、字典 dict、集合 set 等)

而这两个概念的设计逻辑,恰好对应了我们之前提到的 "先描述、再组织" 思想:

  • 类(Class)的本质是 "先描述":通过定义类的成员变量(属性)和成员方法(行为),精准描述一类事物的特征与能力
  • 容器(Container)的本质是 "再组织":当我们用类创建出多个对象(如:多个 "学生" 实例)后,容器负责将这些分散的对象按特定规则(如:顺序、键值映射)组织起来,方便后续的增删查改操作

可以说,面向对象语言中 "类 + 容器" 的组合,正是 "先描述、再组织" 这一管理思想在编程语言层面的经典体现。


简单来说 :操作系统的 "管理",就是用 "数据结构描述资源,用算法操作资源,用中间层传递资源信息",最终实现对计算机软硬件的高效管控 ------ 就像校长用 Excel + 辅导员,实现对学生的有序管理一样。

5. 什么是系统调用和库函数?

要理解系统调用库函数,核心是抓住它们在 "用户程序与操作系统交互" 中的不同定位:

  • 系统调用是操作系统对外开放的 "底层入口"
  • 库函数则是对系统调用(或基础功能)的 "上层封装工具"

系统调用(System Call):操作系统的 "官方接口"

  • 定义:系统调用是操作系统内核为用户程序(或其他系统程序)提供的 底层服务接口 ,是用户空间程序请求内核空间服务的唯一合法途径
    • 简单说:操作系统内核掌握着计算机的核心资源(如:CPU、内存、硬盘、网络卡),普通用户程序没有权限直接操作这些 硬件/资源,只能通过 "系统调用" 向内核 "申请帮忙"
  • 本质"用户态" 与 "内核态" 切换的 "桥梁"
    • 计算机运行时分为用户态 (普通程序运行的空间,权限低)和内核态(操作系统内核运行的空间,权限高)
    • 当用户程序执行系统调用时,会触发 "态切换"------ 从用户态进入内核态,让内核代完成高权限操作(如:读写硬盘、分配内存),操作完成后再切回用户态

库函数(Library Function):程序员的 "便捷工具包"

  • 定义:库函数是编程语言或第三方库提供的 预制函数集合 ,封装了常用的功能逻辑,供程序员直接调用以简化开发,无需重复编写底层代码
    • 简单说 :库函数就像 "现成的工具"------ 比如:要计算平方根,不用自己写迭代算法,直接调用 C 语言标准库的sqrt();要打印内容,不用自己处理显示器硬件,直接调用printf()
  • 本质"对基础功能的封装",封装的内容分两种情况:
    • 基于系统调用封装:大部分与 "系统资源交互" 的库函数,底层其实是调用了系统调用。
      • C 语言的printf(),底层会调用write()系统调用来向终端输出内容
      • fopen()底层会调用open()系统调用来打开文件
    • 纯用户态逻辑封装:部分不涉及系统资源的库函数,底层没有调用系统调用,只是纯用户态的逻辑实现。
      • C 语言的strlen()(计算字符串长度)、memcpy()(内存拷贝)、sqrt()(平方根计算)------ 这些功能只需要操作用户态的内存数据,不需要内核帮忙。

一句话概括:

  • 系统调用:是应用程序向操作系统内核请求服务的唯一正式通道

    • 它是用户态进入内核态的"大门"
    • 从开发视角来看,操作系统对外呈现为一个完整的整体,但会开放部分接口供上层开发使用,这些由操作系统提供的接口就是系统调用
  • 库函数:是预先编写好、可供程序员直接调用的代码集合

    • 它们可能藏在"用户态",也可能通过"大门"去请求操作系统服务
    • 系统调用在功能上较为基础,并且对使用者的要求相对较高。所以,有心的开发者对部分系统调用进行适度封装,进而形成库函数------有了库函数,更上层的用户或者开发者开展二次开发就会便利很多

小故事1:去餐厅吃饭

想象你(应用程序)去一家很高端的餐厅吃饭,后厨重地(内核空间),顾客不能进入。

  • 系统调用:就像是按呼叫铃
    • 这个动作本身是一个明确的、规定好的请求(按铃)厨师(操作系统内核)听到后,会从后厨(内核态 )来到你的餐桌前(用户态)为你服务
    • 你只能通过这种方式和后厨互动,不能自己跑进去。餐厅提供了菜单上所有可能的服务(比如:蒸羊羔、蒸熊掌、蒸鹿尾儿),但这些服务必须由他来完成
  • 库函数:就像是餐厅里的服务员
    • 有些菜 不需要惊动后厨,服务员(库函数)在餐桌旁就能完成。比如:给你倒一杯水、拿一包纸巾
      • 这相当于一个库函数完全在用户空间 自己就完成了工作(例如:C语言标准库中的 strlen 函数计算字符串长度,它只是操作内存,不需要操作系统帮忙)
    • 但大部分菜 需要服务员(库函数)将需求传达至后厨(内核空间),由厨师(操作系统内核)亲自完成。比如:做一道牛排,服务员(库函数)接到你的点单(调用)后,必须替你按铃(发起系统调用),把需求传递给厨师(操作系统内核)。后厨做好后,再由服务员端给你

小故事2:去银行取钱

想象你(应用程序)去一家银行取钱,金库(内核空间),客户不能进入。

  • 进入银行 (运行程序)

    你走进了宽敞明亮的 银行大厅(用户空间) ,这里有很多其它客户(其他程序)在办理业务

  • 寻找帮助 (调用库函数)

    你不知道具体该怎么取钱,于是你找到了 银行柜台(库函数)。柜台提供了很多标准化的服务:

    • 简单服务 :比如咨询汇率、要一张存款单。这些服务柜台自己就能办,不用惊动后面
    • 取钱申请 :但取钱这件事,柜台办不了。不过热情的 柜员(库函数) 帮你填好了 取款单 (格式化参数),上面写清楚了"账号XXX,取款500元"
  • 提交申请 (发起请求)

    你现在有两个选择:

    • A. 直接去找授权柜员 :你拿着填好的单子,直接去找那位有权限进金库的 高级柜员(系统调用)
    • B. 通过大堂经理 :或者,你先把单子交给 大堂经理 (Shell/命令行或图形界面) 。经理一看是取款业务,就会帮你叫号 ,然后引导你去对应的 高级柜员(系统调用) 窗口
  • 核心业务办理 (执行系统调用)
    高级柜员(系统调用) 是唯一连接大厅和金库的通道。他收到你的单子(输入参数)后:

    • 转身进入 金库重地(内核态)
    • 在金库里,他需要请示 行长(操作系统内核的核心代码) ,并按照行长立下的严格规矩(系统)来操作:核对身份、查账本、数钱、记账
    • 所有这些操作,你都看不见也管不着,完全由银行内部完成
  • 返回结果 (系统调用返回)

    高级柜员拿着现金和一张新的账目回单(返回值 ),从金库出来,回到窗口(返回用户态),把东西交给你

  • 业务完成 (函数返回)

    你拿到了钱,整个取款业务圆满完成。你可以选择就此离开,也可以继续让大厅的普通柜员 (库函数) 帮你办点别的,比如:把取出来的钱再重新存进去,哈哈😂

相关推荐
她说彩礼65万3 小时前
C# 特性详解
linux·服务器·c#
程序员buddha4 小时前
C语言数组详解
c语言·开发语言·算法
LSL666_5 小时前
5 Repository 层接口
android·运维·elasticsearch·jenkins·repository
cs麦子7 小时前
C语言--详解--指针--上
c语言·开发语言
Hi202402177 小时前
消除FFmpeg库的SONAME依赖
linux·ffmpeg
电棍2337 小时前
在docker a100云服务器运行vulkan->sapien->robotwin的经验(报错segmentation fault)
运维·docker·容器
gfanbei8 小时前
ARM V8 Cortex R52 上电运行在什么状态?— Deepseek 解答
linux·arm开发·嵌入式硬件
liu****9 小时前
14.日志封装和线程池封装
linux·开发语言·c++
云动雨颤9 小时前
访问宝塔面板安全入口404?SSH命令轻松解决
linux·运维·安全