土法炼钢兴趣小组的算法知识备份

【操作系统百科】POSIX 与 Linux/BSD/Windows 的偏离

文章导航

分类入口
os
标签入口
#posix#linux#freebsd#macos#windows#abi-compat#standards#portability

目录

POSIX(Portable Operating System Interface)是一组定义”类 Unix 操作系统”应该支持的接口的 IEEE/ISO 标准,现行版本是 POSIX.1-2024(俗称 “Issue 8”)。它覆盖系统调用 API、shell 行为、工具命令集。但 POSIX 不是任何操作系统——每个真实的 OS 都是 POSIX 的子集 + 扩展

本文对照 POSIX 基线,列出主要 OS 的扩展、偏离,以及做跨平台系统编程时要提防的坑。

用一张图把 POSIX 在真实 OS 里”被谁扩展、被谁绕开”先建立印象:

flowchart LR
    POSIX[(POSIX.1-2024<br/>基线)]
    POSIX --> Linux[Linux<br/>+epoll/io_uring<br/>+cgroup/ns<br/>+eBPF/seccomp]
    POSIX --> FreeBSD[FreeBSD<br/>+kqueue<br/>+jail/Capsicum<br/>+pf]
    POSIX --> OpenBSD[OpenBSD<br/>+pledge/unveil<br/>+pf]
    POSIX --> macOS[macOS / Darwin<br/>+kqueue<br/>+GCD/XPC<br/>+Mach IPC]
    NT[Windows NT<br/>独立谱系]
    NT --> Win32[Win32 API<br/>CreateProcess / IOCP]
    NT --> WSL1[WSL 1<br/>POSIX 层]
    NT --> WSL2[WSL 2<br/>真 Linux 内核]
    classDef stdn fill:#3fb950,color:#2d333b,stroke:#3fb950;
    classDef ln fill:#388bfd,color:#cdd9e5,stroke:#388bfd;
    classDef nt fill:#a371f7,color:#cdd9e5,stroke:#a371f7;
    class POSIX stdn
    class Linux,FreeBSD,OpenBSD,macOS ln
    class NT,Win32,WSL1,WSL2 nt

绿色是标准基线;蓝色是”在 POSIX 基线之上叠加专属扩展”的 Unix 族;紫色是完全独立谱系的 Windows NT。要记住的是:没有任何真实 OS 等于 POSIX——POSIX 是最小可移植交集,生产软件几乎总要用到某平台的专属扩展才能达到”能用”的性能与安全。下面各节展开每一条扩展。

一、POSIX 的层次

LSB(Linux Standard Base)是 POSIX 的 Linux 侧子集 + 发行约束(文件系统布局、库版本)。但 LSB 在 2015 年后基本停滞,现实里”Linux = glibc + 你的发行版”。

二、Linux-only 的接口

这些接口在 glibc 里常见,但不在 POSIX 里:

接口 首次出现 替代的 POSIX
epoll_* 2.5.44 select、poll(POSIX)
eventfd 2.6.22 pipe
signalfd 2.6.22 sigaction+sigprocmask
timerfd_* 2.6.25 timer_create(POSIX.1b)
inotify_* 2.6.13
fanotify_* 2.6.37
pidfd_* 5.3
io_uring_* 5.1 AIO(POSIX.1b)
clone / clone3 2.x / 5.3 fork、posix_spawn
unshare 2.6.16
setns 3.0
memfd_create 3.17 shm_open
userfaultfd 4.3
seccomp 2.6.12 / 3.5
Landlock 5.13
openat2 5.6 openat
statx 4.11 stat
copy_file_range 4.5 自行读写
prctl / pidns 相关 2.x
sched_setaffinity 2.5.8 无(pthread_attr_setaffinity_np 是扩展)
set_robust_list / futex 2.6.17

注意:POSIX 的 AIO(aio_readaio_write)在 Linux 上是基于线程池的用户态实现(glibc 或 libaio 的 fallback),性能差;真正高效的异步 I/O 在 Linux 上要用 io_uring(见 G-57)。这是”POSIX 标准但实现差 vs 非标准但好用”的经典对立。

三、BSD 扩展

FreeBSD、OpenBSD、NetBSD、macOS(基于 Darwin,继承部分 BSD)各自维护的非 POSIX 扩展:

macOS 特有

iOS 在 macOS 内核基础上做了大量 sandbox(Seatbelt)、entitlement、codesigning 加固,API 对开发者暴露的是 Foundation/Cocoa,而非 POSIX 系统接口。

四、Windows NT 的独立谱系

Windows NT(1993)不是 Unix。它的内核 API 在 ntdll.dll 级别,上层是 Win32(kernel32.dll、user32.dll 等),POSIX 兼容通过子系统实现。

4.1 WSL:两代兼容

4.2 关键差异

维度 Windows NT POSIX / Linux
进程创建 CreateProcess(单步加载新镜像) fork + exec
文件句柄 HANDLE(opaque) int fd
等待原语 WaitForMultipleObjects(统一) select/poll/epoll + signal + waitpid 等
异步 I/O IOCP(Overlapped I/O) AIO/epoll/io_uring
线程 CreateThread(1:1,无用户态调度) pthread(1:1),最近 M:N 讨论
大小写敏感 默认不敏感(per-directory 可开启) 敏感
路径分隔符 \(也接受 / /
文件权限 ACL DAC + capability + ACL(可选)
信号 ConsoleCtrl / Exception handling signal
fork 不支持 支持(历史包袱)

4.3 “fork 的败北”

fork 是 Unix 最古老的原语之一,但它和现代硬件、现代程序(线程、大内存、JIT)配合得极差:

替代:

POSIX.1-2024 把 posix_spawn 地位抬高,但 fork 不会被移除(稳定 ABI)。

五、signal 方言

POSIX 定义了 signal 语义,但各家在细节上差异:

signal 在跨平台代码里是噩梦之源。现代实践:尽量用 signalfd / kqueue / IOCP 把 signal 转成 I/O 事件,在主事件循环里同步处理,不要用异步 handler。

六、文件系统语义的偏离

6.1 路径大小写

Linux/BSD:大小写敏感。macOS:默认 case-preserving but case-insensitive(HFS+ 和 APFS 默认)。Windows:默认不敏感(NTFS 支持可配置)。

这是跨平台构建系统的永恒地雷——在 macOS 上编译通过的代码在 Linux 上因为 #include "Foo.h" 找不到 foo.h 失败。

6.2 符号链接

POSIX 定义 symlink;Windows NT 支持但历史复杂:

WSL、Git for Windows 常因此爆炸。

6.3 文件名字符集

Linux:字节序列,除 / 和 NUL 外任何都可。POSIX 建议 UTF-8 locale。Windows:UTF-16 底层,文件系统层 case-folding 表有古怪规则。macOS:HFS+ 强制 NFD 归一化(NFC 会被转换)——Git 在 macOS 上对中文/日文文件名要小心。

6.4 inode 概念

POSIX 的 stat 结构包含 st_ino。Linux、BSD 按 inode 展示;Windows 上只能拿 NTFS 的 File ID(64-bit,不保证所有 FS 都有)。跨平台工具(git, rsync)处理这个差异有大量 workaround。

6.5 mmap 与 file hole

Linux、BSD、Windows 都支持 sparse file(hole),但 API 不同:

七、时间与定时器

时间的 “绝对稳定” 是跨平台库(zstd benchmark、Rust std::time::Instant)的长期难题。

八、进程控制

九、多线程与并发

十、I/O 多路复用的分岔路

机制 所在 OS 模型
select/poll 所有 POSIX level-triggered,线性扫描
epoll Linux only level / edge triggered,就绪列表
kqueue BSD / macOS filter-based,统一文件/信号/定时器
IOCP Windows completion-based(异步)
io_uring Linux submission/completion ring,异步

这是近 20 年高性能网络编程的分叉核心——每个 OS 有自己的答案。跨平台库(libuv、libevent、asio)的大部分代码都在弥合这些差异。

十一、错误码与错误模型

errno.h 的跨平台兼容层(glibc、musl、LLVM libc)是个默默做了很多工作的地方。

十二、写跨平台系统代码的建议

  1. 默认写 Linux,再适配:90% 的服务器平台是 Linux;先让核心高效,再做其他 OS 分支
  2. 抽象层不要太厚:不要自己造一个 “跨平台 I/O” 巨型抽象。具体的 I/O primitive(epoll / io_uring / kqueue / IOCP)有各自最佳调用模式,共性少
  3. macOS 是 Linux-like,但 Darwin 内核异常多:FS 行为、VM 行为、信号、EFAULT 语义,默认当它是”像 BSD 的 BSD 的 BSD”
  4. Windows 不要用 POSIX 层:MinGW/MSYS 的 POSIX 兼容是”能跑”,不是”跑得好”;真要 Windows native 用 IOCP / WaitOnAddress / Overlapped
  5. CI 全平台:Linux + macOS + Windows + FreeBSD + ARM64 全跑。Rust 和 Go 的丰富 target 生态是它们的隐形优势
  6. 文件系统语义写测试:大小写、symlink、长路径、非 ASCII、sparse、FS 的 atime/mtime 精度

十三、标准的意义与局限

POSIX 让 Unix 世界保持了某种形态一致性,但也正是”保持一致”拖累了 Unix 的现代化——POSIX 委员会审慎,标准化滞后于实现 10 年是常态。现代有影响力的 API 几乎都是平台创新后再被标准引入的:

给你的启示:别被标准绑架。了解标准是地基,但生产系统要用实际最强的原语。如果你写的是数据库/消息队列/网络服务,Linux 专有 API(io_uring、cgroup v2、eBPF、membarrier)常常是性能差距的来源,放弃跨平台兼容是值得的 trade-off。

下一篇 A-08 把一些 OS 相关的”常识错觉”——零拷贝不等于零开销、微内核不等于安全、实时不等于快、容器不等于虚拟机——一起讲清楚。


参考文献


上一篇内核与用户态的边界 下一篇关于 OS 的工程常识错觉

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-04-17 · os

【操作系统百科】Unix 谱系与设计遗产:Multics、Plan 9、Linux

要理解 Linux 的很多古怪决定,得回到 Multics、Unix V6/V7、BSD 的历史语境。本文沿时间线梳理 Unix 家谱,挑出每一代留下的设计遗产——fork/exec、一切皆文件、管道、可重定向的 stdin/stdout、9P、命名空间——并指出哪些被 Linux 发扬,哪些被抛弃,哪些仍在 Plan 9 的血脉里孤独活着。

2026-04-17 · os

【操作系统百科】系统调用 ABI:x86_64 / arm64 / riscv / Windows NT 对照

系统调用是 OS 最稳定的接口。本文拆解 Linux syscall 的参数寄存器约定、返回值规范(负 errno 与 2-value ABI)、x86_64 SYSCALL、arm64 SVC、RISC-V ECALL、Windows NT 的 int 2e/syscall/SYSENTER 历史;说明为什么 Linux 承诺 \"don't break userspace\"、什么东西算 syscall ABI、vDSO 如何用共享内存加速、Go/musl/glibc 各自怎么实现 syscall stub。


By .