FantasticMao 技术笔记
BlogGitHub
  • README
  • C & Unix
    • C
      • 《C 程序设计语言》笔记
      • C 语言中的陷阱
      • CMake 示例
      • GNU make
      • LLVM Clang
      • Nginx 常用模块
      • Vim 常用命令
    • Unix-like
      • 《深入理解计算机系统》笔记
      • 《UNIX 环境高级编程》笔记 - UNIX 基础知识
      • 《UNIX 环境高级编程》笔记 - 文件 IO
      • 《UNIX 环境高级编程》笔记 - 标准 IO 库
      • 《鳥哥的 Linux 私房菜》笔记 - 目录配置
      • 《鳥哥的 Linux 私房菜》笔记 - 认识与学习 bash
      • 《鳥哥的 Linux 私房菜》笔记 - 任务管理
      • OpenWrt 中的陷阱
      • iptables 工作机制
  • Go
    • 《A Tour of Go》笔记
    • Go vs C vsJava
    • Go 常用命令
    • Go 语言中的陷阱
  • Java
    • JDK
      • 《Java 并发编程实战》笔记 - 线程池的使用
      • 设计模式概览
      • 集合概览
      • HashMap 内部算法
      • ThreadLocal 工作机制
      • Java Agent
    • JVM
      • 《深入理解 Java 虚拟机》笔记 - Java 内存模型与线程
      • JVM 运行时数据区
      • 类加载机制
      • 垃圾回收算法
      • 引用类型
      • 垃圾收集算法
      • 垃圾收集器
    • Spring
      • Spring IoC 容器扩展点
      • Spring Transaction 声明式事务管理
      • Spring Web MVC DispatcherServlet 工作机制
      • Spring Security Servlet 实现原理
    • 其它
      • 《Netty - One Framework to rule them all》演讲笔记
      • Hystrix 设计与实现
  • JavaScript
    • 《写给大家看的设计书》笔记 - 设计原则
    • 《JavaScript 权威指南》笔记 - jQuery 类库
  • 数据库
    • ElasticSearch
      • ElasticSearch 概览
    • HBase
      • HBase 数据模型
    • Prometheus
      • Prometheus 概览
      • Prometheus 数据模型和指标类型
      • Prometheus 查询语法
      • Prometheus 存储原理
      • Prometheus vs InfluxDB
    • Redis
      • 《Redis 设计与实现》笔记 - 简单动态字符串
      • 《Redis 设计与实现》笔记 - 链表
      • 《Redis 设计与实现》笔记 - 字典
      • 《Redis 设计与实现》笔记 - 跳跃表
      • 《Redis 设计与实现》笔记 - 整数集合
      • 《Redis 设计与实现》笔记 - 压缩列表
      • 《Redis 设计与实现》笔记 - 对象
      • Redis 内存回收策略
      • Redis 实现分布式锁
      • Redis 持久化机制
      • Redis 数据分片方案
      • 使用缓存的常见问题
    • MySQL
      • 《高性能 MySQL》笔记 - Schema 与数据类型优化
      • 《高性能 MySQL》笔记 - 创建高性能的索引
      • 《MySQL Reference Manual》笔记 - InnoDB 和 ACID 模型
      • 《MySQL Reference Manual》笔记 - InnoDB 多版本
      • 《MySQL Reference Manual》笔记 - InnoDB 锁
      • 《MySQL Reference Manual》笔记 - InnoDB 事务模型
      • B-Tree 简述
      • 理解查询执行计划
  • 中间件
    • gRPC
      • gRPC 负载均衡
    • ZooKeeper
      • ZooKeeper 数据模型
    • 消息队列
      • 消息积压解决策略
      • RocketMQ 架构设计
      • RocketMQ 功能特性
      • RocketMQ 消息存储
  • 分布式系统
    • 《凤凰架构》笔记
    • 系统设计思路
    • 系统优化思路
    • 分布式事务协议:二阶段提交和三阶段提交
    • 分布式系统的技术栈
    • 分布式系统的弹性设计
    • 单点登录解决方案
    • 容错,高可用和灾备
  • 数据结构和算法
    • 一致性哈希
    • 布隆过滤器
    • 散列表
  • 网络协议
    • 诊断工具
    • TCP 协议
      • TCP 报文结构
      • TCP 连接管理
由 GitBook 提供支持
在本页
  • UNIX 体系结构
  • 系统调用和库函数
  1. C & Unix
  2. Unix-like

《UNIX 环境高级编程》笔记 - UNIX 基础知识

UNIX 体系结构

从严格意义上说,可将操作系统定义为一种软件,它控制计算机硬件资源,提供程序运行环境。我们通常将这种软件称为 内核(kernel),因为它相对较小,而且位于环境的核心。

内核的接口被称为 系统调用(system call)。公共函数库 构建在系统调用接口之上,应用程序 既可以使用公共函数库,也可以使用系统调用。shell 是一个特殊的应用程序,为运行其它应用程序提供了一个接口。

+----------------------------+
|               Application  |
|    +---------+             |
|    |  Shell  |             |
|    |  +------+--------+    |
|    |  |  System Call  |    |
|    |  |  +--------+   |    |
|    +--|  | Kernel |   |    |
|    |  |  +--------+   |    |
|    |  +---------------+    |
|    |  Public Library  |    |
|    +------------------+    |
|                            |
+----------------------------+

从广义上说,操作系统包括了内核和一些其它软件,这些软件使得计算机能够发挥作用,并使计算机具有自己的特性。这里所说的其它软件包括系统实用程序(system utility)、应用程序、shell 以及公用函数库等。

例如,Linux 是 GNU 操作系统(比如 Ubuntu)使用的内核。

系统调用和库函数

所有的操作系统都提供多种服务的入口点,由程序向内核请求服务。各种版本的 UNIX 实现都提供良好定义、数量有限、直接进入内核的入口点,这些入口点被称为系统调用。

系统调用接口总是在《UNIX 程序员手册》的第 2 部分中说明,是用 C 语言定义的,与具体的 UNIX 实现技术无关。

UNIX 系统调用的使用方式是为每个系统在标准 C 库中设置一个具有相同名字的函数。用户进程用标准 C 函数的调用方式来调用这些函数,然后,这些函数会用系统所要求的技术来调用相应的内核服务。从应用角度考虑,可将系统调用看作为 C 函数。

《UNIX 程序员手册》的第 3 部分定义了程序员可以使用的公共函数库。虽然这些函数可能会调用一个或多个内核的系统调用,但是它们并不是内核的入口点。

从实现角度来看,系统调用和库函数之间有着本质的区别,但从应用角度来看,这些区别并不重要。如果可以的话,我们可以替换库函数,但是系统调用通常是不能被替换的。

以存储空间分配函数 malloc 为例。有多种方法可以进行存储空间分配,以及与其相关的无用空间的回收操作(最佳适应、首次适应等),并不存在对所有程序都是最优解的一种技术。UNIX 系统调用中处理存储空间分配的是 sbrk(2),它不是一个通用的存储管理器。它按指定字节数增加或减少进程地址空间,如何管理该地址空间却取决于进程的具体行为。存储空间分配函数 malloc(3) 实现一种特定类型的分配,如果我们不喜欢其操作方式,则可以定义自己的 malloc 函数,但它很可能会使用 sbrk 系统调用。事实上,有很多软件包(例如 Redis 中可使用的 jemalloc)使用 sbrk 系统调用实现自己的存储空间分配算法。

内核中的 sbrk 系统调用分配一块空间给进程,而库函数 malloc 则在用户层次管理这一空间。

应用程序既可以调用系统调用,也可以调用库函数。很多库函数则会调用系统调用。

+---------------+                +------------------------+
| +-----------+ |                |          +-----------+ |
| |Application| |                |          |Application| |
| +-----------+ |                |          +-----------+ |
|    ^ ^ ^      |  User Process  | +---------+   ^        |
|    v v v      |                | |C Library|   |        |
|  +--------+   |                | +---------+   |        |
|  | malloc |   |                |     ^         |        |
|  +--------+   |                |     |         |        |
+---------------+                +-----|---------|--------+
      ^ ^ ^                            |         |
      | | |                            |         |
      v v v                            v         v
+---------------+                +------------------------+
|     |sbrk|    |                |                        |
|     +----+    |   Kernel       |      System Call       |
|               |                |                        |
+---------------+                +------------------------+

系统调用和库函数之间的另一个区别是:系统调用通常提供一种最小接口,而库函数通常提供比较复杂的功能。 从 sbrk 系统调用和 malloc 库函数之间的差别中可以看到这一点。比较不带缓冲的 I/O 函数和标准 I/O 函数时,也能看到这种差别。

最后更新于1年前