Langchain系列文章目录

01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
08-【万字长文】MCP深度解析:打通AI与世界的“USB-C”,模型上下文协议原理、实践与未来

Python系列文章目录

PyTorch系列文章目录

机器学习系列文章目录

深度学习系列文章目录

Java系列文章目录

JavaScript系列文章目录

Python系列文章目录

Go语言系列文章目录

Docker系列文章目录

操作系统系列文章目录

01-【操作系统-Day 1】万物之基:我们为何离不开操作系统(OS)?
02-【操作系统-Day 2】一部计算机的进化史诗:操作系统的发展历程全解析
03-【操作系统-Day 3】新手必看:操作系统的核心组件是什么?进程、内存、文件管理一文搞定
04-【操作系统-Day 4】揭秘CPU的两种工作模式:为何要有内核态与用户态之分?
05-【操作系统-Day 5】通往内核的唯一桥梁:系统调用 (System Call)


文章目录

  • Langchain系列文章目录
  • Python系列文章目录
  • PyTorch系列文章目录
  • 机器学习系列文章目录
  • 深度学习系列文章目录
  • Java系列文章目录
  • JavaScript系列文章目录
  • Python系列文章目录
  • Go语言系列文章目录
  • Docker系列文章目录
  • 操作系统系列文章目录
  • 摘要
  • 一、为何需要系统调用:应用程序的“权力”局限
    • 1.1 系统调用的核心作用
  • 二、系统调用(System Call)的本质
    • 2.1 什么是系统调用?
    • 2.2 系统调用与普通函数调用的区别
  • 三、系统调用的“穿越之旅”:从用户态到内核态
    • 3.1 核心机制:陷入(Trap)
    • 3.2 详细流程剖析
        • (1) 准备阶段:传递参数
        • (2) 执行阶段:陷入内核
        • (3) 硬件响应:切换状态
        • (4) 内核处理:执行服务
        • (5) 返回阶段:功成身退
        • (6) 回到用户程序
    • 3.3 一个具体实例:以 Linux `write()` 为例
  • 四、包罗万象:系统调用的分类
  • 五、总结


摘要

本文是“操作系统从入门到精通”系列的第五篇,我们将深入探讨连接应用程序与操作系统内核的唯一桥梁——系统调用(System Call)。在上一篇文章中,我们理解了为何要有内核态与用户态之分,本文将聚焦于应用程序如何跨越这道“权限鸿沟”,安全地请求操作系统提供服务。我们将从系统调用的概念与必要性出发,详细拆解一次完整的系统调用过程,包括陷入(Trap)、用户态到内核态的切换、内核服务执行及返回的全过程。最后,我们会对常见的系统调用进行分类,帮助读者建立一个清晰、完整的知识图谱。无论您是编程新手还是希望夯实基础的进阶者,本文都将为您揭开系统调用神秘的面纱。

一、为何需要系统调用:应用程序的“权力”局限

在上一章中,我们学习了 CPU 的两种工作状态:用户态(User Mode)和内核态(Kernel Mode)。这种设计的核心目的是保护和安全。操作系统内核作为掌管所有硬件资源的“大管家”,运行在至高无上的内核态,可以执行任何指令。而我们日常编写和运行的应用程序,则被限制在用户态,它们的“权力”非常有限,无法执行某些高风险的“特权指令”,例如直接访问硬件、修改页表、开关中断等。

那么,问题来了:如果一个应用程序(比如一个文本编辑器)想要读取硬盘上的文件内容,或者一个网络浏览器想要发送数据到网卡,这些操作都涉及到直接与硬件打交道,应用程序本身又没有这个权限,该怎么办?

这就好比一个普通市民(应用程序)想办理一项需要政府部门(操作系统内核)审批的业务(访问硬件资源)。市民不能直接闯入政府办公室自己动手盖章,而是需要遵循一套合法的流程,向指定的办事窗口(系统调用接口)提交一份申请书(发起系统调用),由窗口的工作人员(内核中的服务例程)来完成后续的操作。

因此,系统调用正是操作系统提供的、允许用户态程序向内核“提需求”的唯一、合法且受控的通道

1.1 系统调用的核心作用

  • 提供统一接口:操作系统将对底层硬件的复杂、多样化操作封装成一系列标准、统一的函数接口(即系统调用),应用程序开发者无需关心具体硬件型号和驱动细节,只需调用这些接口即可。
  • 保证系统安全:通过这道唯一的桥梁,内核可以对应用程序的每一个请求进行严格的审查。比如,检查文件访问权限、检查内存地址是否越界等。只有合法、安全的请求才会被执行,从而有效防止了恶意或有缺陷的程序破坏整个系统。

二、系统调用(System Call)的本质

2.1 什么是系统调用?

系统调用 (System Call),从本质上讲,是操作系统内核提供给应用程序的一组编程接口 (API)。当应用程序需要执行任何超越其权限范围的操作时,它就会请求内核代为执行。这个“请求”动作,就是一次系统调用。

我们可以将系统调用理解为应用程序写给内核的一封详尽的**“委托书”**。这封委托书上清晰地写明了:

  1. 希望内核做什么:例如,“我想读取一个文件”,这就是请求的服务类型。
  2. 完成任务需要哪些信息:例如,要读取哪个文件(文件名)、把内容读到哪里(内存地址)、要读多少(字节数)等,这些都是传递给内核的参数。

2.2 系统调用与普通函数调用的区别

初学者很容易将系统调用与我们编程时常用的普通函数调用(例如,自己定义的 add(a, b) 函数)混淆。虽然它们在 C 语言等高级语言中的调用形式看起来很相似(如 read(...) vs add(...)),但其底层实现和执行流程却有天壤之别。

特性普通函数调用 (Function Call)系统调用 (System Call)
执行空间用户空间内完成,不涉及状态切换。跨越用户空间内核空间,涉及状态切换。
执行状态调用前和调用后,CPU 都处于用户态调用时,CPU 从用户态切换到内核态,返回时再切回用户态
执行开销开销小,仅涉及函数栈帧的创建和销毁。开销大,包含状态切换、参数传递、内核验证等多个步骤。
实现方由应用程序自身或其链接的库提供。操作系统内核实现。
调用方式直接的指令跳转到函数地址。通过特殊的**“陷入”指令 (Trap Instruction)** 来触发。

三、系统调用的“穿越之旅”:从用户态到内核态

系统调用的核心在于它如何实现从低权限的用户态“穿越”到高权限的内核态。这个过程并非简单的函数跳转,而是一个由硬件和操作系统协同完成的、严谨而精妙的过程。

3.1 核心机制:陷入(Trap)

应用程序无法直接调用位于内核空间的函数。为了启动系统调用,应用程序会执行一条特殊的CPU指令,这条指令被称为陷入指令(Trap Instruction)或系统调用指令。在不同的CPU架构上,这条指令的名字可能不同,例如在 x86 架构中,早期使用 int 0x80(软件中断),现在则推荐使用更高效的 syscall 指令。

执行陷入指令会引发一个硬件事件,这个事件会主动地让CPU暂停当前的用户程序,并将控制权转移给操作系统内核中预先设定好的一个特定处理程序,这个过程就叫做陷入 (Trap)

3.2 详细流程剖析

一次完整的系统调用,就像一次精心策划的“短途旅行”,往返于用户态和内核态之间。下面我们以一个简化的模型来剖析其详细步骤:

(1) 准备阶段:传递参数

应用程序在执行陷入指令之前,必须先准备好“委托书”的内容。

  1. 指定服务:将唯一的系统调用号(一个整数,代表要请求哪种服务,例如 1 代表 write2 代表 open)放入一个约定的寄存器中(如 rax 寄存器)。
  2. 提供参数:将调用该服务所需的其他参数(如文件描述符、内存缓冲区地址、要读写的字节数等)依次放入其他约定的寄存器中。如果参数过多,也可能通过栈来传递。
(2) 执行阶段:陷入内核

用户程序执行 syscall(或类似的)陷入指令。

(3) 硬件响应:切换状态

CPU硬件检测到这条指令后,会自动完成以下一系列动作:

  1. 切换到内核态:将 CPU 的状态位从用户态修改为内核态。
  2. 保存“案发现场”:将当前的用户程序执行位置(程序计数器 PC)和其他关键寄存器的值保存到内核指定的内存区域(通常是内核栈)中。这至关重要,以便将来能准确返回。
  3. 跳转到处理程序:根据陷入指令的类型,跳转到内核中预设的**系统调用总入口(Trap Handler)**开始执行。
(4) 内核处理:执行服务

控制权现在完全交给了内核。

  1. 查找服务例程:系统调用处理程序首先从寄存器中取出系统调用号
  2. 参数验证:它会像一个严格的门卫,检查用户程序传递过来的参数是否合法(例如,指针是否指向了用户空间合法的内存地址)。
  3. 调用具体实现:如果验证通过,内核会根据系统调用号在一个名为系统调用表 (System Call Table) 的数组中找到对应的内核函数(例如 sys_write, sys_open),并执行它。
  4. 执行真正的操作sys_write 等内核函数开始真正地与硬件交互,完成用户请求的任务。
(5) 返回阶段:功成身退
  1. 准备返回值:内核服务完成后,会将结果(例如成功写入的字节数,或是一个错误码)存放到一个约定的寄存器中(通常也是 rax)。
  2. 恢复“案发现场”:内核执行一条特殊的返回指令(如 sysexitiret),这条指令会让硬件:
    • 恢复用户寄存器:将之前保存的用户程序状态(PC、其他寄存器)从内核栈中恢复出来。
    • 切换回用户态:将 CPU 状态位从内核态改回用户态。
(6) 回到用户程序

控制权回到用户程序,它从刚才执行 syscall 指令的下一条指令处继续执行,并可以从指定的寄存器中获取系统调用的返回结果。至此,一次完整的系统调用结束。

3.3 一个具体实例:以 Linux write() 为例

让我们看看当你在 C 代码中写下一行 write(1, "hello\n", 6); 时,幕后发生了什么。

#include <unistd.h>int main() {// 向标准输出(文件描述符为 1)写入字符串 "hello\n"// 这个函数调用最终会触发一次系统调用write(1, "hello\n", 6); return 0;
}

这段代码的执行流程会大致遵循以下路径(以 x86-64 Linux 为例):

  1. 用户态:程序调用 C 库 glibc 提供的 write 函数封装。
  2. 用户态glibcwrite 函数负责准备工作:
    • 将系统调用号 1 (代表 __NR_write) 放入 rax 寄存器。
    • 将第一个参数 1 (文件描述符) 放入 rdi 寄存器。
    • 将第二个参数 "hello\n" 的内存地址放入 rsi 寄存器。
    • 将第三个参数 6 (长度) 放入 rdx 寄存器。
  3. 用户态glibc 执行 syscall 指令。
  4. 硬件:CPU 捕获指令,保存用户态上下文,切换到内核态,跳转到内核的系统调用入口点。
  5. 内核态:内核的系统调用处理程序读取 rax 的值为 1,知道用户想执行 write
  6. 内核态:内核检查 rdi, rsi, rdx 中的参数,确认文件描述符 1 是合法的,并且内存地址指向用户空间。
  7. 内核态:内核调用内部的 sys_write 函数,该函数找到与文件描述符 1 关联的设备驱动(通常是终端驱动),并将数据 “hello\n” 发送给它。
  8. 内核态sys_write 执行完毕,返回成功写入的字节数 6。这个返回值被放入 rax 寄存器。
  9. 内核态:内核执行 sysexit 指令。
  10. 硬件:CPU 恢复用户态上下文,切换回用户态
  11. 用户态glibcwrite 函数封装从 rax 寄存器中取回返回值 6,并将其作为 C 函数的返回值。程序继续执行。

四、包罗万象:系统调用的分类

系统调用覆盖了应用程序与操作系统交互的方方面面。为了便于管理和理解,通常将它们按功能分为以下几大类:

分类说明常见系统调用举例 (Linux)
进程控制 (Process Control)负责进程的创建、终止、等待、属性设置等。是多任务操作系统的基石。fork(), clone(), execve(), exit(), wait4(), getpid()
文件操作 (File Manipulation)负责文件的创建、删除、打开、关闭、读写和属性设置。open(), close(), read(), write(), lseek(), stat()
设备管理 (Device Management)负责请求和释放设备、读写设备数据等,通常通过文件操作接口实现。ioctl(), read(), write() (作用于设备文件时)
信息维护 (Information Maintenance)负责获取或设置系统及进程的信息,如时间、系统数据、进程属性等。time(), gettimeofday(), getrusage()
通信 (Communication)负责进程间的通信(IPC),是构建复杂协作应用的基础。pipe(), socket(), shmget() (共享内存), msgget() (消息队列)
内存管理 (Memory Management)负责内存的分配和映射。brk(), mmap()

五、总结

本文深入探讨了操作系统中承上启下的关键概念——系统调用。通过这篇文章,我们应该理解以下核心要点:

  1. 存在的意义:系统调用是操作系统为用户程序提供的、用于请求内核服务的唯一、安全、标准的接口,它是隔离用户态和内核态、保护系统安全的基石。
  2. 核心过程:一次系统调用的生命周期始于用户态的陷入(Trap)指令,经历由硬件辅助的上下文切换进入内核态,由内核执行具体服务,最后再切换回用户态并返回结果。
  3. 成本考量:与普通函数调用相比,系统调用因为涉及两次上下文切换(用户态 -> 内核态 -> 用户态),其执行开销要大得多。因此,在性能敏感的应用中,应避免频繁且不必要的系统调用。
  4. 功能范畴:系统调用涵盖了进程控制、文件操作、设备管理、进程间通信等所有需要内核介入的功能,构成了现代应用程序能够运行的底层支持框架。

理解了系统调用,就等于掌握了应用程序与操作系统对话的语言。在后续的章节中,无论是讨论进程管理、内存管理还是文件系统,我们都会发现,它们所有功能的最终实现,都离不开一次次的系统调用。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/914274.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/914274.shtml
英文地址,请注明出处:http://en.pswp.cn/news/914274.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

完整 Spring Boot + Vue 登录系统

项目名称&#xff1a;springboot-vue-login-template✅ 功能一览模块功能后端Spring Boot MyBatis Plus JWT Shiro数据库MySQL 用户表前端Vue3 Element Plus Axios登录流程用户名/密码验证 → 返回 Token → 存储 LocalStorage权限控制拦截器校验 Token Shiro 角色权限跨…

Redis 基础详细介绍(Redis简单介绍,命令行客户端,Redis 命令,Java客户端)

1. Redis 简介Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的内存数据库&#xff0c;遵守 BSD 协议&#xff0c;它提供了一个高性能的键值&#xff08;key-value&#xff09;存储系统&#xff0c;常用于缓存、消息队列、会话存储等应用场景。1.1 特征丰富…

C/C++数据结构之多维数组

概述多维数组&#xff0c;实际上就是“数组的数组”。最常见的是二维数组&#xff0c;就像一个表格&#xff0c;拥有行和列。而三维数组则可以想象为多个这样的表格堆叠起来形成的一个立方体。依此类推&#xff0c;我们可以构建四维、五维甚至更高维度的数组。多维数组主要用于…

[Rust 基础课程]选一个合适的 Rust 编辑器

市面上现在有很多编辑器都可以开发 Rust&#xff0c;很多都是以安装 Rust 插件的形式来对 Rust 做支持&#xff0c;本课程使用 RustRover&#xff0c;如果你喜欢其他的编辑器&#xff0c;可以自己捣鼓下。 RustRover https://www.jetbrains.com/rust/ jetbrains 专门对于 Ru…

【零基础学AI】第37讲:提示词工程(Prompt Engineering)

本节课你将学到 理解提示词工程的核心原理 掌握5种实用的Prompt设计模式 学会优化提示词的评估方法 实现一个智能问答系统优化案例 开始之前 环境要求 Python 3.8安装包&#xff1a;pip install openai tiktokenOpenAI API密钥&#xff08;免费注册&#xff1a;https://plat…

莫兰迪色系工作总结汇报PPT模版分享

莫兰迪色工作总结PPT模版&#xff0c;莫兰迪调色板PPT模版&#xff0c;莫兰迪色系高级简约PPT模版&#xff0c;莫兰迪色系工作汇报&#xff0c;莫兰迪总结汇报模版 莫兰迪色系工作总结汇报PPT模版分享&#xff1a;https://pan.quark.cn/s/35bcaa03c837

uniapp的app项目,某个页面长时间无操作,返回首页

最开始想做成一个公共的&#xff0c;完全提取出来的一个组件&#xff0c;组件设置背景透明&#xff0c;到时候哪个页面需要&#xff0c;直接引入组件就可以了&#xff0c;所以最开始做的是一个vue的组件&#xff0c;在组件中&#xff0c;监听页面的touchstart&#xff0c;但是这…

【实证分析】上市公司绿色战略数据集(2000-2023年)

数据简介&#xff1a;绿色战略是指企业根据其所处的外部环境&#xff08;包括“绿色浪潮”等环保趋势&#xff09;和企业自身的经营条件&#xff0c;为实现企业生存与发展质量的持续提升&#xff0c;而对企业生产经营活动进行绿色化改造的总体规划。这包括制定企业绿色可持续发…

【SpringAI】7. 基于 milvus 的向量检索

SpringAI 基于 milvus 的向量检索 向量数据库可以使用 milvus&#xff0c;redis,Elasticsearch 等&#xff0c;本文以 milvus 为例&#xff1a; 1. 启动milvus 为了尽可能快速上手springai的vectordb功能&#xff0c;我们推荐使用云上的milvus&#xff0c;注册就能创建免费的…

如何使用数字化动态水印对教育视频进行加密?

文章目录前言一、什么是数字化动态水印二、使用数字化动态水印对教育视频加密的好处&#xff1f;三、数字化动态水印的实现原理四、如何实现数字化动态水印对教育视频加密总结前言 教育资源数字化蓬勃发展的今天&#xff0c;优质视频课程已成为机构的核心知识资产。然而&#…

解决bash终端的路径名称乱码问题

解决bash终端的路径名称乱码 默认打开了zsh&#xff0c;当我输入bash后&#xff0c;就出现了乱码 (context_rag) [23fanyaohead1]~/mycode-thesis% bash (context_rag) [%n%m]%~%#乱码原因排查 我遇到了终端乱码问题&#xff0c;需要检查当前的终端环境和编码设置&#xff0c;下…

【深度学习】【入门】Sequential的使用和简单神经网络搭建

1.Sequential的概念它是一种按顺序封装神经网络层的容器&#xff0c;能让层按照添加顺序依次执行计算&#xff0c;简化网络搭建流程2.Sequential的作用1.代码简洁化对比不用 Sequential 时手动搭建层的繁琐代码&#xff08;如每层需手动定义并连接&#xff09;&#xff0c;展示…

前端开发中的资源缓存详解

资源缓存用于缓存静态资源,良好的缓存策略可以减少资源重复加载进而提高网页的整体加载速度。 通常浏览器缓存策略分为两种:强缓存和协商缓存,当然还包括 service worker。 浏览器在资源加载时,根据请求头中的 expires 和 cache-control 值来判断是否命中强缓存,命中则直…

零基础入门指南:华为数通认证体系详解

一、华为数通认证的定位与行业价值华为数通认证&#xff08;Datacom&#xff09;是ICT领域核心方向&#xff0c;覆盖路由器、交换机等网络基础设备技术&#xff0c;被誉为“网络行业的骨骼”。2020年升级为Datacom认证体系&#xff0c;新增SDN、VXLAN、网络自动化等前沿技术&am…

超低功耗CC2340R SimpleLink™ 系列 2.4GHz 无线 MCU支持BLE5.3/Zigbee/Thread/专有协议

CC2340R SimpleLink™ 系列 2.4GHz 无线 MCU支持BLE5.3/Zigbee/Thread/专有协议优势简介性能介绍应用场景优势简介 CC2340R SimpleLink™ 系列器件为 2.4GHz 无线微控制器 (MCU)&#xff0c;面向低功耗 Bluetooth5.3、Zigbee、Thread 和专有 2.4GHz 应用。这些器件针对低功耗无…

若依前后端分离Vue3版本接入阿里云OSS

一、引入依赖首先在commom 模块的pom 下面引入 阿里云OSS 的 依赖<!-- 阿里云oss --><dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.17.4</version></depende…

2025年微软mos备考攻略-穷鬼版

说实话&#xff0c;微软MOS认证是微软官芳推出的办公软件方面的认证&#xff0c;考试难度真的不大&#xff0c;完全没必要报班&#xff0c;自学完全OK&#xff01;一、25 年报考MOS认证详情报名时间&#xff1a;随时可以在官网或ji构报名&#xff08;ji构报名会送备考资料&…

数据库版本自动管理

FlywayDB 是一款 开源数据库版本管理工具&#xff0c;开发中将表结构的变更或数据初始化脚本维护好&#xff0c;更新到测试环境或线上发版启动服务的时候&#xff0c;会检测版本号自动执行数据库变更&#xff0c;可以减少每次发版到其他环境的人工执行操作。 工作流程初始化阶段…

解决Linux绑定失败地址已使用(端口被占用)的问题

文章目录解决 bind failed: Address already in use 问题一、问题原因1. **端口已经被其他程序占用**2. **端口处于 TIME_WAIT 状态**3. **未正确关闭套接字**二、如何排查和解决问题1. **确认端口是否被占用**2. **查找并杀掉占用端口的进程**3. **等待端口释放&#xff08;TI…

Ragas的Prompt Object

Prompt在Ragas中被用在各种指标、合成数据生成任务中。同时也为提供了替换各种自动以提示词的方式。Ragas提供了如下几种Prompt Objects。 instruction:prompt的基础组成,通过自然语言清晰的描述LLM需要完成的任务。在prompt object中用instruction变量定义。few-shot exampl…