POSIX IPC 与共享内存与 POSIX 定时器与异步 I/O

共 46 题
📑 题目列表 46 题
#
★★★

1. POSIX IPC 三件套,消息队列(mq)、信号量(sem)、共享内存(shm)

POSIX IPC 三件套(消息队列、信号量、共享内存)如何理解?

  • POSIX IPC 类型
  • 消息队列/信号量/共享内存
  • 各自用途

POSIX IPC 三件套:消息队列(mq_open/mq_send/mq_receive)——按路径名标识的命名消息队列,进程间传消息(支持优先级),适合"消息传递"型通信;信号量(sem_open/sem_wait/sem_post)——命名信号量,进程间同步/互斥(控制共享资源访问),用于同步;共享内存(shm_open + mmap)——命名共享内存,进程间共享数据区,性能最高(直接读写共享内存),适合大数据量交换。三者组合:共享内存传数据 + 信号量同步 + 消息队列通知,是 POSIX IPC 的典型搭配。取舍:共享内存最快但需同步,消息队列有格式但慢,信号量用于同步。

三件套互补:共享内存做数据交换(快)、信号量做同步(协调)、消息队列做消息传递(结构化)。工程上常组合使用。

#
★★

2. System V IPC 与 POSIX IPC 的对比,key vs name、生命周期

System V IPC 与 POSIX IPC 的对比:key vs name、生命周期如何理解?

  • System V vs POSIX IPC
  • key vs name
  • 生命周期

System V IPC(msgget/semget/shmget)与 POSIX IPC(mq_open/sem_open/shm_open)差异:标识——System V 用 key(key_t,如 ftok 生成)标识,POSIX 用名字(name,如 "/mq" 路径名)标识;生命周期——System V IPC 不随进程退出而自动删除(需显式 ipcrm),POSIX IPC 对象在引用计数为 0 且删除后清理(shm_unlink 等);接口——POSIX 接口更现代(fd 化、可配合 select/epoll),System V 传统。取舍:POSIX IPC 更现代、可移植、接口友好,System V 更传统、部分系统支持。工程上:新代码用 POSIX IPC,兼容旧系统用 System V。

差异在"标识(key vs 名字)"与"生命周期(显式删除 vs 引用计数)"。POSIX IPC 用名字、更现代、可配 fd。

#
★★

3. Unix domain socket(AF_UNIX)的 stream 与 datagram 模式

Unix domain socket(AF_UNIX)的 stream 与 datagram 模式如何理解?

  • AF_UNIX
  • stream vs datagram
  • 特性

Unix domain socket(AF_UNIX)本地进程间通信,两种模式:SOCK_STREAM——字节流,面向连接,可靠有序(类似 TCP 但本地),消息边界由应用处理;SOCK_DGRAM——数据报,无连接,保留消息边界(类似 UDP 但可靠,本地不丢包不乱序),每个 sendto 对应一个 recvfrom 消息。特性:本地内核内通信,无网络开销,可传文件描述符(SCM_RIGHTS)。取舍:stream 适合流式数据/长连接,datagram 适合固定消息(保留边界、可靠)。工程上:本地 IPC 用 AF_UNIX,stream 用于请求响应流,datagram 用于消息队列式。

stream 可靠有序流(无边界),datagram 保留消息边界(本地可靠)。AF_UNIX 本地高效、可传 fd,是高性能本地 IPC。

#
★★

4. mq_open 的 POSIX 消息队列与 mq_send/mq_receive 的优先级消息

mq_open 的 POSIX 消息队列与 mq_send/mq_receive 的优先级消息如何工作?

  • mq_open 创建消息队列
  • 优先级消息
  • mq_send/mq_receive

mq_open 创建/打开命名消息队列(指定名字、属性如最大消息数/大小),mq_send 发送消息(指定优先级,unsigned int),mq_receive 接收(按优先级取:高优先级先取,同优先级 FIFO)。优先级消息:消息带优先级,接收时优先取最高优先级消息,用于优先级调度(高优先级请求先处理)。mq_attr 可设 mq_maxmsg(最大消息数)、mq_msgsize(消息大小)。工程上:mq 用于进程间可靠消息传递,优先级用于分级处理;注意绑定限制(mq_maxmsg 与 RLIMIT)。

消息队列支持优先级(高优先先取)。mq_open 配置队列属性,mq_send/mq_receive 收发带优先级的消息。适合消息传递型 IPC。

#
★★

5. shm_open + mmap 的 POSIX 共享内存创建与映射

shm_open + mmap 的 POSIX 共享内存创建与映射如何工作?

  • shm_open
  • mmap 映射
  • 共享内存

POSIX 共享内存:shm_open 创建/打开命名共享内存对象(返回 fd,类似文件),用 ftruncate 设置大小,再 mmap 映射到进程地址空间,多个进程 shm_open 同一名字并 mmap 后共享同一物理内存。共享内存是数据交换最快的 IPC(直接读写共享内存,无拷贝)。需配合同步(信号量/互斥锁)避免并发访问冲突。删除:shm_unlink 取消名字(对象在引用计数为 0 时清理)。工程上:大数据量共享(如多进程共享缓存)用 shm_open+mmap,配合信号量同步。

shm_open 提供命名共享内存对象,mmap 映射到各进程地址空间共享。无拷贝最快,但需同步访问。

int fd = shm_open("/shm", O_CREAT|O_RDWR, 0666);
ftruncate(fd, 4096);
void *p = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
#
★★

6. pipe 只能用于有亲缘关系的进程、FIFO 可用于无亲缘进程,Unix domain socket 相比它们在双向通信与传递文件描述符上有何优势?

pipe、FIFO 与 Unix domain socket 在双向通信与传递文件描述符上有何差异?

  • pipe/FIFO/UDS
  • 双向通信
  • 传递 fd

pipe——只能用于有亲缘关系(父子)的进程,单向(半双工)匿名管道;FIFO(命名管道)——可用于无亲缘进程(通过路径名),单向;Unix domain socket(AF_UNIX)——双向(全双工),可用于无亲缘进程,且可通过 SCM_RIGHTS 传递文件描述符(把 fd 从一个进程传给另一个)。优势:UDS 双向通信(无需两条管道)、可传 fd(如把 socket/文件 fd 传给服务进程)、可靠有序、本地高效。对比:pipe/FIFO 单向,需两条实现双向;UDS 原生双向 + 可传 fd。工程上:需双向+传 fd 用 UDS,简单单向用 pipe/FIFO。

核心优势是"双向 + 传 fd"。pipe/FIFO 单向,UDS 全双工且能传文件描述符,是功能更强的本地 IPC。

#
★★

7. POSIX 消息队列(mq_open/mq_send,按路径名标识、支持优先级接收)与 System V 消息队列(msgget/msgsnd,用 key 与消息类型)在接口与生命周期上有何差异?

POSIX 消息队列与 System V 消息队列在接口与生命周期上有何差异?

  • POSIX vs System V 消息队列
  • 接口差异
  • 生命周期

POSIX 消息队列(mq_open/mq_send/mq_receive)——用路径名标识(如 "/mq"),支持优先级接收(mq_receive 按优先级取),接口 fd 化(可与 select/epoll 配合),生命周期由引用计数管理(mq_unlink 时清理)。System V 消息队列(msgget/msgsnd/msgrcv)——用 key 标识(ftok),用消息类型(long mtype)而非优先级(msgrcv 按类型取),接口传统(无 fd),生命周期需显式删除(msgctl IPC_RMID),不随进程退出自动清理。差异:标识(路径名 vs key)、接收(优先级 vs 消息类型)、接口(fd 化 vs 传统)、生命周期(自动清理 vs 显式删除)。工程上:POSIX 更现代可移植,System V 传统。

差异在"标识(名 vs key)、接收(优先级 vs 类型)、接口(fd vs 传统)、生命周期(引用计数 vs 显式删除)"。POSIX 更现代。

#
★★

8. IPC 性能对比,pipe vs UDS vs TCP loopback vs shared memory

IPC 性能对比:pipe vs UDS vs TCP loopback vs shared memory 如何排序?

  • IPC 性能
  • 各类 IPC 开销
  • 对比

IPC 性能大致排序(从快到慢):shared memory(共享内存)——直接读写共享内存,无拷贝/系统调用(配合同步),最快;Unix domain socket(UDS)——内核内通信,无网络协议栈开销,无需跨网络,较快;pipe/FIFO——内核缓冲管道,有拷贝但无网络开销,中等;TCP loopback——经完整 TCP/IP 协议栈(尽管回环),有协议处理与缓冲开销,较慢。对比本质:shared memory 无拷贝(最快),UDS 省网络栈,pipe 有拷贝,TCP loopback 有完整协议栈开销。工程上:极致性能用 shared memory,通用本地用 UDS,跨进程流式用 pipe,网络/跨机用 TCP。

性能排序:shared memory > UDS > pipe > TCP loopback。shared memory 无拷贝,TCP 有协议栈开销,UDS 介于其间。

#
★★

9. mlock/munlock 的内存锁定与实时系统应用

mlock/munlock 的内存锁定与实时系统应用如何理解?

  • mlock/munlock
  • 内存锁定
  • 实时应用

mlock 把内存页锁定在物理内存(不可被换出/交换),munlock 解除锁定。用途:实时系统/关键路径——防止内存被 swap 到磁盘导致访问延迟抖动(major fault);密码/密钥内存——锁定避免被换出到磁盘(泄露风险);确定性要求——保证内存访问延迟可预测。注意:mlock 会增加物理内存占用(锁定的页不能回收),需谨慎控制锁定范围;RLIMIT_MEMLOCK 限制可锁定的内存量。工程上:实时任务/敏感数据用 mlock 锁定关键内存,避免 swap 抖动与磁盘泄露。

mlock 锁定内存防 swap,保访问延迟确定性与敏感数据不进磁盘。实时系统关键路径用,但需注意锁定内存量与权限。

#
★★

10. shm_open 建立共享内存后用 mmap 映射,多个进程如何配合 sem_open/POSIX 信号量同步对共享区的访问?

多个进程如何配合 shm_open+mmap 与 sem_open/POSIX 信号量同步共享区访问?

  • 共享内存 + 信号量
  • 同步配合
  • 多进程

多进程共享内存访问需同步:进程用 shm_open+mmap 映射同一共享内存,同时用 sem_open 创建命名信号量(跨进程同步),在访问共享区前 sem_wait(加锁),访问后 sem_post(解锁),保证互斥。命名信号量靠名字(如 "/sem")让多个进程共享同一信号量。流程:每个进程先 shm_open(同名字)+ sem_open(同名字),mmap 共享区,访问时 sem_wait/sem_post 保护。工程上:共享内存 + 命名信号量是标准的多进程共享数据同步组合,信号量放共享内存或独立命名。

共享内存提供数据,命名信号量提供同步。进程用同一名字的 sem_open 获得同一信号量,sem_wait/sem_post 保护共享区访问。

#
★★

11. POSIX 信号量在多进程同步的"无主"清理难题

POSIX 信号量在多进程同步的"无主"清理难题如何理解?

  • POSIX 信号量
  • 无主清理
  • 进程崩溃

POSIX 命名信号量(sem_open)的"无主"清理难题:若其中一个进程(持有信号量)崩溃,信号量可能被"永久锁定"(sem_wait 后未 sem_post 即崩溃),其他进程无法获得信号量而阻塞。与 robust mutex 不同,POSIX 信号量没有自动恢复机制(无 EOWNERDEAD 类似机制),信号量无"主"概念,无法自动检测持有者崩溃。治理:避免在信号量临界区做可能崩溃的操作、用超时/看门狗、把信号量重建/重置(但需协调)、或用 robust mutex(进程间共享)替代信号量。工程上:信号量临界区保持短小,崩溃后需外部干预重置,或用 robust 同步原语。

信号量无主,持有者崩溃则无人解锁(无自动恢复)。这是信号量 vs robust mutex 的劣势,需短临界区或外部重置。

#
★★

12. mq 的"消息优先级"在调度中的实际意义

mq 的"消息优先级"在调度中的实际意义是什么?

  • 消息优先级
  • 调度
  • 工程意义

消息队列的优先级(mq_send 的优先级)决定接收时的处理顺序:mq_receive 总是先取最高优先级的消息,同优先级内按 FIFO 顺序。工程意义:优先级让关键/紧急消息优先被消费,避免被大量普通消息淹没(如告警、控制指令优先于普通日志)。实现:POSIX 消息队列 mq_send 指定优先级(0 到 MQ_PRIO_MAX),mq_receive 按优先级排序取出。调度上:高优先级消息先出队,低优先级可能被"饿死"(持续有高优先级时)。工程上:用优先级区分重要/普通消息,但需注意低优先级饥饿与限流。

优先级决定出队顺序:高优先级先取,同优先级 FIFO。用于关键消息优先,但需防低优先级饥饿。

#
★★

13. POSIX timer_create 的 CLOCK_REALTIME、CLOCK_MONOTONIC、CLOCK_PROCESS_CPUTIME 的选择

POSIX timer_create 的 CLOCK_REALTIME、CLOCK_MONOTONIC、CLOCK_PROCESS_CPUTIME 如何选择?

  • 时钟类型
  • CLOCK_REALTIME/MONOTONIC/CPUTIME
  • 选择

timer_create 的时钟决定到期语义:CLOCK_REALTIME——墙上时钟(受系统时间/NTP 调整影响),适合"真实时间"定时(如定时任务按墙钟);CLOCK_MONOTONIC——单调时钟(不受 NTP 调整、只增不减),适合"相对时长"定时(不受时间调整干扰,稳定);CLOCK_PROCESS_CPUTIME——进程 CPU 时间(计时进程消耗的 CPU 时间,非墙钟),适合 CPU 时间预算/超时。选择:定时器到期间隔(相对时长)用 MONOTONIC(稳定),日期/墙钟调度用 REALTIME,CPU 时间限制用 CPUTIME。工程上:相对定时器用 CLOCK_MONOTONIC 避免 NTP 跳变影响。

时钟选择看"语义":REALTIME 受时间调整、MONOTONIC 稳定不受 NTP、CPUTIME 计 CPU 时间。相对定时用 MONOTONIC。

#
★★

14. lio_listio 的批量异步 I/O 提交

lio_listio 的批量异步 I/O 提交如何工作?

  • lio_listio
  • 批量异步 I/O
  • 提交

lio_listio 是 POSIX AIO 的批量提交接口:一次调用提交多个异步 I/O 请求(一组 aio_controlblock),通过 mode 控制(LIO_WAIT 等待全部完成 / LIO_NOWAIT 立即返回),sigevent 指定完成通知。适合批量操作(一堆小 I/O 并发提交),减少逐个提交的开销,提升 I/O 并发。提交后各请求独立完成,用 aio_error/aio_return 检查或 sigevent 通知。工程上:批量小 I/O 用 lio_listio 并发提交,提高吞吐;注意与 libaio 的 io_submit 对比(POSIX 的批量)。

lio_listio 一次提交多个异步 I/O,LIO_WAIT/NOWAIT 控制等待,sigevent 通知,适合批量并发 I/O。

#
★★

15. alarm() 与 setitimer() 的传统定时器 API

alarm() 与 setitimer() 的传统定时器 API 如何理解?

  • alarm/setitimer
  • 传统定时器
  • 语义

alarm() 设置一次性定时器(以秒为单位,到期发 SIGALRM),简单但只能整数秒、单次;setitimer() 更灵活:可设间隔定时器(it_value 首次到期 + it_interval 周期),支持三种定时器(ITIMER_REAL 墙钟、ITIMER_VIRTUAL 进程用户 CPU 时间、ITIMER_PROF 用户+内核 CPU 时间),精度微秒级,到期发信号。相比 alarm,setitimer 支持周期、子秒、多种计时器。工程上:需要周期定时/子秒精度用 setitimer,简单一次性用 alarm;现代偏好 POSIX timer(timer_create)或 timerfd。

alarm 一次性秒级,setitimer 支持周期/子秒/多种时钟。现代用 POSIX timer/timerfd 更灵活,setitimer 是传统接口。

#
★★

16. timer_create 的 SIGEV_SIGNAL 与 SIGEV_THREAD 通知方式在开销与线程安全上有何差异,SIGEV_THREAD 的回调线程从何而来?

timer_create 的 SIGEV_SIGNAL 与 SIGEV_THREAD 通知方式在开销与线程安全上有何差异?SIGEV_THREAD 的回调线程从何而来?

  • SIGEV_SIGNAL vs SIGEV_THREAD
  • 开销与线程安全
  • 回调线程来源

SIGEV_SIGNAL——定时器到期发信号(异步信号,处理器受异步信号安全限制,只能做简单操作),开销低(无线程创建),但处理受限;SIGEV_THREAD——到期时内核创建新线程调用回调函数(可做任意操作,无需受限),开销高(每次到期创建线程,需线程创建+调度),且回调线程是"内核创建的临时线程"(由内核/运行时创建,非用户显式创建),需注意回调线程的退出与同步。对比:SIGNAL 开销低但处理受限,THREAD 可自由处理但开销高(线程创建)。工程上:轻量简单用 SIGNAL(配合 sigwait),复杂处理用 THREAD 但需注意线程创建开销。

SIGEV_SIGNAL 信号处理受限,SIGEV_THREAD 创建临时线程回调(开销高但灵活)。SIGEV_THREAD 的回调线程由系统创建,非用户线程。

#
★★

17. POSIX 定时器的线程安全与多线程 timer_create

POSIX 定时器的线程安全与多线程 timer_create 如何理解?

  • 定时器线程安全
  • 多线程 timer_create
  • 通知

POSIX 定时器(timer_create)是进程级资源(非线程级),可在多线程中创建/使用。线程安全:定时器到期通知(SIGEV_SIGNAL 发信号、SIGEV_THREAD 创建线程)由系统调度,回调/信号处理需考虑线程安全;timer_create/timer_settime/timer_delete 是线程安全的(POSIX 要求)。多线程注意:同一 timer 的到期处理(回调)可能并发/串行触发,需保证回调线程安全;timer 的 t_id 在所有线程可见。工程上:多线程用 timer_create 需注意到期回调的线程安全(用锁/无锁),避免并发访问共享状态。

POSIX 定时器进程级、线程安全,回调处理需自行保证线程安全,注意到期回调可能并发。

#
★★

18. shm 的"删除 vs 取消映射"语义差异

shm 的"删除 vs 取消映射"语义差异如何理解?

  • shm_unlink vs munmap
  • 删除/取消映射
  • 引用计数

共享内存的删除与取消映射语义不同:shm_unlink(删除)——删除共享内存对象的名字(移除命名),但对象内存还在(若仍有进程映射),直到最后一个映射(munmap/进程退出)后清理;munmap(取消映射)——把共享内存从调用进程的地址空间解除映射(不再可访问),但对象名字仍存在(其他进程可映射)。即:shm_unlink 删名字,munmap 断映射,对象在"名字删除 + 引用计数为 0"时彻底销毁。工程上:进程退出前 munmap(释放映射),管理生命周期用 shm_unlink(清理对象),注意顺序。

shm_unlink 删名字(对象仍存到引用为 0),munmap 断当前进程映射。对象在名字删+引用为 0 时销毁。

#
★★

19. eventfd 的事件通知与计数器语义

eventfd 的事件通知与计数器语义如何理解?

  • eventfd
  • 计数器语义
  • 事件通知

eventfd 创建一个可读写的文件描述符,内部维护一个 64 位计数器,用于内核态/用户态事件通知。语义:write 把值加到计数器,read 读取并清零(或按 EFD_SEMAPHORE 减 1),可配合 epoll 等待可读(计数器非 0 时可读)。计数器语义:可以作为计数器(累加)或事件标志(非 0 表示有事件)。用途:事件通知(如"有数据要处理")、信号量(EFD_SEMAPHORE)、跨线程/进程唤醒。工程上:eventfd 用于轻量事件通知(配合 epoll),比管道/信号更高效,计数器语义灵活。

eventfd 是带 64 位计数器的 fd 事件通知,write 累加 read 清零,可当事件标志或信号量,配合 epoll 高效。

#
★★

20. aio_read/aio_write 的 POSIX 异步 I/O API 与 io_uring 的对比

aio_read/aio_write 的 POSIX 异步 I/O API 与 io_uring 有何对比?

  • POSIX AIO
  • io_uring
  • 对比

POSIX AIO(aio_read/aio_write/aio_error/aio_return)是标准异步 I/O API,可读/写完成后通知(sigevent)或轮询;但 Linux 上 glibc 用线程池实现(伪异步,用户线程阻塞在同步 I/O),场景有限。io_uring 是 Linux 5.1+ 的原生异步 I/O:用共享内存队列(SQ/CQ)提交/回收 I/O,支持大量异步操作、减少系统调用、支持多类型(read/write/fsync/网络/同步),性能高、可扩展。对比:POSIX AIO 可移植但 Linux 实现是伪异步(线程池),io_uring 真异步、高效但仅 Linux。工程上:Linux 高性能异步 I/O 用 io_uring,需可移植用 POSIX AIO。

POSIX AIO 可移植但 Linux 是线程池伪异步,io_uring 真异步高效(共享队列、少 syscall)但仅 Linux。高性能场景用 io_uring。

#
★★

21. clock_gettime 的纳秒级时间获取与 CLOCK_BOOTTIME

clock_gettime 的纳秒级时间获取与 CLOCK_BOOTTIME 如何理解?

  • clock_gettime
  • 纳秒精度
  • CLOCK_BOOTTIME

clock_gettime 获取高精度时间(纳秒级,struct timespec),支持多种时钟:CLOCK_REALTIME(墙上时钟,受 NTP)、CLOCK_MONOTONIC(单调时钟,不受 NTP 但系统挂起时不计)、CLOCK_BOOTTIME(单调时钟,包含系统挂起(suspend)时间)。CLOCK_BOOTTIME 的价值:单调 + 计入挂起,用于需"真实经过时间"(含休眠)的定时/测量(如进程挂起后仍正确计时)。工程上:性能测量用 CLOCK_MONOTONIC(不受 NTP 干扰),需含挂起时间用 CLOCK_BOOTTIME,墙钟用 REALTIME。clock_gettime 的 vDSO 优化使纳秒级获取开销很低。

clock_gettime 纳秒级,CLOCK_BOOTTIME 是含挂起时间的单调时钟,用于需真实经过时间的场景。vDSO 使开销极低。

#
★★

22. timer_delete 与 timer 资源回收

timer_delete 与 timer 资源回收如何理解?

  • timer_delete
  • 资源回收
  • 定时器清理

timer_delete 删除定时器(timer_create 创建的),释放定时器资源(内核定时器、内核资源)。删除后定时器不再触发。注意:删除前若有未完成的到期回调(SIGEV_THREAD 创建的线程),需确保回调完成/清理,避免资源泄漏;timer_delete 后 timer 的 t_id 失效。资源回收:不 delete 的定时器在进程退出时由内核回收,但长期运行进程应显式 delete 释放资源。工程上:定时器用完显式 timer_delete,处理未完成回调(同步/等待),避免泄漏。

timer_delete 释放定时器资源,需注意未完成回调的清理。长期运行进程应显式删除定时器防泄漏。

#
★★

23. timer_settime 的首次到期(it_value)与周期(it_interval)的工程语义

timer_settime 的首次到期(it_value)与周期(it_interval)的工程语义如何理解?

  • timer_settime
  • it_value/it_interval
  • 周期定时

timer_settime 设置定时器:it_value(首次到期时间)——定时器到首次到期经过的时间;it_interval(周期)——首次到期后每次重复到期的间隔。若 it_interval 非 0,定时器周期性触发;若 it_interval 为 0,定时器只触发一次(一次性)。工程语义:首期(it_value)控制"何时开始",周期(it_interval)控制"重复频率"。工程上:先设 it_value(如 5s)再设 it_interval(如 1s)实现"5s 后每 1s 触发",只设 it_value 实现延迟一次性定时。注意长周期高负载下可能丢周期(timer_getoverrun)。

it_value 是首次到期(开始时间),it_interval 是周期(重复间隔)。it_interval=0 则一次性,非 0 则周期。

#
★★

24. POSIX 1003.1b 实时扩展的 sigevent 通知模式

POSIX 1003.1b 实时扩展的 sigevent 通知模式如何理解?

  • sigevent
  • 通知模式
  • 实时扩展

POSIX 1003.1b 实时扩展定义 sigevent(信号事件结构)用于异步操作完成通知(AIO、定时器、消息队列):sigev_notify 指定通知模式——SIGEV_NONE(无通知)、SIGEV_SIGNAL(发信号,用 sigev_signo)、SIGEV_THREAD(创建线程回调,用 sigev_notify_function)、SIGEV_THREAD_ID(投递到指定线程,Linux 扩展)。sigevent 把"完成通知"统一为信号/线程/无三种模式,配套 sigev_value 携带数据。工程上:根据通知处理方式选模式(信号处理、线程回调、指定线程),实现异步操作的完成通知。

sigevent 统一异步完成通知(信号/线程/无)。SIGEV_SIGNAL 发信号、SIGEV_THREAD 回调线程、SIGEV_NONE 无通知。

#
★★

25. timerfd 与 epoll 协同的事件循环定时器

timerfd 与 epoll 协同的事件循环定时器如何工作?

  • timerfd
  • epoll 协同
  • 事件循环定时器

timerfd 创建定时器文件描述符(timerfd_create),到期时变为可读(read 读到期次数),配合 epoll 用 fd 事件方式处理定时器——把 timerfd 加入 epoll,epoll_wait 时定时器到期作为可读事件处理。优点:定时器作为 fd 事件,与其他 I/O(socket、signalfd)统一在事件循环中处理,无需信号/线程,同步安全。timerfd_settime 设置首次到期与周期。工程上:高性能事件循环(网络服务)用 timerfd+epoll 统一管理定时器与 I/O,定时器到期即触发事件处理。

timerfd 把定时器变成 fd 事件,配合 epoll 统一事件循环处理,避免信号/线程,适合与 I/O 混合的定时器。

#
★★

26. timerfd_create 的"定时器即文件描述符"模式

timerfd_create 的"定时器即文件描述符"模式如何理解?

  • timerfd_create
  • 定时器即 fd
  • 模式

timerfd_create 把定时器实现为文件描述符("定时器即文件描述符"模式):创建的 fd 在定时器到期时变为可读,read 读取到期次数(uint64_t),可用 select/poll/epoll 等待。模式价值:定时器获得标准 fd 的语义(可被 epoll 监听、可被传递、可被 I/O 复用),与事件循环/多路复用统一,无需信号处理器或线程回调。timerfd 支持 CLOCK_REALTIME/MONOTONIC/BOOTTIME。工程上:需要统一事件循环、可被 epoll 监听、可传 fd 的定时器用 timerfd,是事件驱动服务的主流定时器方案。

timerfd 让定时器成为 fd,享受 fd 的所有能力(epoll、传 fd、多路复用),是事件驱动定时器的标准做法。

#
★★

27. POSIX AIO 与 libaio 在 Linux 的实现差异

POSIX AIO 与 libaio 在 Linux 的实现差异如何理解?

  • POSIX AIO vs libaio
  • 实现差异
  • 真异步/伪异步

POSIX AIO(aio_read 等)在 Linux 的 glibc 实现用"用户态线程池":为每个异步 I/O 创建线程,线程内做阻塞同步 I/O,回调后通知——"伪异步"(线程池阻塞,不真正异步,扩展性差)。libaio(Linux AIO)是内核原生异步 I/O:io_submit 提交到内核,内核真正异步完成(不阻塞用户线程),支持 O_DIRECT 等,但接口传统、限制多(不支持缓冲 I/O)。

POSIX AIO 在 glibc 是"用户态线程池 + 阻塞 I/O"(伪异步,可移植),libaio 是内核真异步(io_submit,仅 Linux、需 O_DIRECT)。差异核心是"是否内核真正异步"。

#
★★

28. POSIX 异步 I/O 在内核版本(Linux 5.x)的支持演进

POSIX 异步 I/O 在内核版本(Linux 5.x)的支持演进如何理解?

  • Linux AIO 演进
  • io_uring
  • 内核支持

Linux 异步 I/O 演进:早期 libaio(io_submit)内核实异步但限制多(需 O_DIRECT、不支持缓冲 I/O)。Linux 5.1 引入 io_uring——新一代异步 I/O 框架,用共享内存队列(SQ/CQ)提交/回收,支持缓冲 I/O、多数 I/O 类型(read/write/fsync/网络/定时器)、减少系统调用、高效。Linux 5.x 持续完善 io_uring(加特性、优化)。影响:POSIX AIO 在 Linux 的"伪异步"(线程池)被 io_uring 的"真异步"取代,高性能场景从 libaio 迁移到 io_uring。工程上:Linux 5.x+ 用 io_uring 做高效异步 I/O,替代 POSIX AIO/libaio。

Linux 5.1+ 的 io_uring 是真正异步 I/O 的演进,支持缓冲 I/O、少 syscall、高效,取代 POSIX AIO 的线程池伪异步。

#
★★

29. 周期性定时器在高负载下可能发生过期累积,timer_getoverrun 如何报告丢失的周期数?

周期性定时器在高负载下可能发生过期累积,timer_getoverrun 如何报告丢失的周期数?

  • 周期定时器
  • 过期累积
  • timer_getoverrun

周期性定时器的高负载下,信号队列可能饱和,导致多次到期未投递(overrun,过期累积)。timer_getoverrun 返回"上次定时器到期后丢失的到期次数"(前一次信号投递后到本次之间跳过的周期数),用于报告过期的累积量。用途:接收端(信号处理器)用 timer_getoverrun 计算实际经过的时间(即使信号丢失,也能知道过了多少周期),避免"定时器只触发一次但实际过了很多周期"的误判。工程上:高负载周期定时器用 timer_getoverrun 补偿丢失的周期,保证计时准确。

高负载下定时器信号可能丢周期,timer_getoverrun 报告丢失的周期数,接收端据此补偿计时。

#
★★

30. UDS 的 file system namespace(抽象命名空间 abstract)与文件路径

UDS 的 file system namespace(抽象命名空间 abstract)与文件路径如何理解?

  • AF_UNIX namespace
  • abstract vs 文件路径
  • 差异

Unix domain socket 的两类命名空间:文件路径(file system namespace)——socket 绑定到文件系统路径(如 /tmp/sock),可通过文件系统访问/管理(权限、ls),但会创建文件(需清理);抽象命名空间(abstract namespace)——socket 名以空字节开头(如 "\0name"),不创建文件系统文件,仅内核命名空间内可见,无文件系统权限控制,但无需清理文件、不受文件系统限制。差异:文件路径有文件可见/权限可管理,abstract 无文件但更"纯内核"。工程上:需文件系统权限/可管理用路径,快速临时 socket 用 abstract(不产生文件)。

文件路径 namespace 创建可见文件(可管理权限),abstract namespace 不创建文件(纯内核、无文件权限)。按需选择。

#
★★

31. mmap 的 MAP_SHARED、MAP_PRIVATE、MAP_ANONYMOUS 标志的工程语义

mmap 的 MAP_SHARED、MAP_PRIVATE、MAP_ANONYMOUS 标志的工程语义如何理解?

  • mmap 标志
  • MAP_SHARED/PRIVATE/ANONYMOUS
  • 语义

mmap 标志:MAP_SHARED——映射共享(写映射的文件/共享内存,其他进程可见,写回文件),用于进程间共享(共享内存映射);MAP_PRIVATE——映射私有(写时复制,写不写回文件,也不影响其他进程),用于私有文件映射;MAP_ANONYMOUS——匿名映射(无文件,用于内存分配/堆),可与 SHARED/PRIVATE 组合。工程语义:MAP_SHARED 用于共享内存/文件共享(写可见),MAP_PRIVATE 用于私有读文件(写 COW 不写回),MAP_ANONYMOUS 用于匿名内存(malloc 大块、线程栈)。选型:共享需 MAP_SHARED,私有读 MAP_PRIVATE,纯内存 MAP_ANONYMOUS。

MAP_SHARED 共享可见(写回文件),MAP_PRIVATE 私有写时复制(不写回),MAP_ANONYMOUS 匿名内存。按共享/私有/文件需求选。

#
★★

32. munmap 的 msync 同步策略与崩溃一致性

munmap 的 msync 同步策略与崩溃一致性如何理解?

  • msync
  • 同步策略
  • 崩溃一致性

msync 把 MAP_SHARED 映射的内存页同步到文件(刷盘),munmap 解除映射(不保证写回)。写 MAP_SHARED 映射后,数据可能仍在内存/页缓存,需 msync(MS_SYNC 同步/ MS_ASYNC 异步)才落到文件。崩溃一致性:若进程崩溃前未 msync,MAP_SHARED 的修改可能丢失(未刷盘);MS_SYNC 同步刷盘保证崩溃后数据在文件,但开销大。工程上:共享映射的持久化数据需在关键点 msync(MS_SYNC) 保证崩溃一致;普通共享内存(不落盘)无需 msync。munmap 前 msync 确保数据落盘。

msync 将共享映射刷盘(MS_SYNC 同步保证崩溃一致),munmap 只解除映射。持久化共享数据需 msync 防崩溃丢失。

#
★★

33. sem_open 的命名信号量与 sem_init 的无名信号量边界

sem_open 的命名信号量与 sem_init 的无名信号量边界如何理解?

  • sem_open vs sem_init
  • 命名/无名信号量
  • 使用边界

sem_open(命名信号量)——通过名字(如 "/sem")创建/打开,可用于"无亲缘关系的进程"间同步(不同进程用同一名字打开同一信号量),有名字持久化;sem_init(无名信号量)——创建一个未命名的信号量(需要分配内存),共享方式:可在同一进程内线程共享(pshared=0),或放在共享内存中供进程共享(pshared=1)。边界:跨进程(尤其无亲缘)用命名信号量(sem_open),同进程线程或共享内存中的进程用无名信号量(sem_init)。工程上:进程间同步用 sem_open,线程/共享内存同步用 sem_init。

命名信号量按名字跨进程共享,无名信号量需置于共享内存/线程共享。跨进程用 sem_open,线程/共享内存用 sem_init。

#
★★

34. SO_REUSEADDR 允许绑定处于 TIME_WAIT 的本地地址,SO_REUSEPORT 允许多个 socket 绑定完全相同的地址端口,两者语义与典型用途有何不同?

SO_REUSEADDR 与 SO_REUSEPORT 的语义与典型用途有何不同?

  • SO_REUSEADDR
  • SO_REUSEPORT
  • 语义与用途

SO_REUSEADDR——允许立即绑定处于 TIME_WAIT 状态的本地地址(端口),避免服务重启时因残留 TIME_WAIT 连接无法绑定端口;SO_REUSEPORT——允许多个 socket 绑定完全相同的地址端口,内核负载均衡(按哈希分发连接)到多个 socket/进程,用于多进程/多线程监听同端口实现横向扩展。差异:SO_REUSEADDR 解决"TIME_WAIT 端口占用"(重启绑定),SO_REUSEPORT 实现"多 socket 共享端口均衡"(多监听者)。用途:服务重启用 SO_REUSEADDR,多进程并发监听用 SO_REUSEPORT(性能扩展)。

SO_REUSEADDR 处理 TIME_WAIT 复用,SO_REUSEPORT 多 socket 共享端口内核均衡。前者重启,后者扩展。

#
★★

35. mmap 的 MAP_FIXED 与地址冲突的处理

mmap 的 MAP_FIXED 与地址冲突如何处理?

  • MAP_FIXED
  • 地址冲突
  • 处理

MAP_FIXED 要求 mmap 在指定地址(精确)映射,若该地址已被占用,会覆盖/替换已有的映射(危险,可能破坏现有映射)。地址冲突:若指定地址与已有映射重叠,MAP_FIXED 会覆盖,导致数据/代码损坏。处理:避免用 MAP_FIXED 覆盖已有映射;用 MAP_FIXED_NOREPLACE(Linux 4.17+)——若指定地址已被占用则返回错误(不覆盖);或先检查地址可用性(不保证)。工程上:一般不用 MAP_FIXED(除非需要精确地址,如 JIT 的固定地址),需固定地址时用 MAP_FIXED_NOREPLACE 防覆盖。

MAP_FIXED 覆盖指定地址的已有映射(危险),MAP_FIXED_NOREPLACE 不覆盖并报错。需固定地址时用后者防覆盖。

#
★★

36. POSIX AIO(aio_read、aio_write)在 glibc 实现的"用户线程 + sync I/O"的伪异步?

POSIX AIO(aio_read、aio_write)在 glibc 实现的"用户线程 + sync I/O"的伪异步如何理解?

  • glibc POSIX AIO
  • 用户线程 + sync I/O
  • 伪异步

glibc 的 POSIX AIO(aio_read/aio_write)实现为"用户线程 + 同步 I/O":为每个异步请求创建/复用用户态线程,线程内执行阻塞的同步 I/O(read/write),完成后通知(sigevent/回调)。这是"伪异步"——从应用看是异步(不阻塞调用线程),但底层是线程池阻塞在同步 I/O,不是内核真正异步(不减少线程数、扩展性差、受线程数限制)。应用把"异步"委托给线程池,I/O 本身仍阻塞。工程上:glibc POSIX AIO 适合小规模/可移植,高性能真异步用 io_uring/libaio。

glibc 用线程池做同步 I/O 模拟异步(伪异步),线程阻塞不减少线程,扩展性差。真异步用 io_uring。

#
★★

37. libaio(Linux 原生 AIO)在 Linux kernel 的真异步 I/O 与 POSIX AIO 的工程边界?

libaio(Linux 原生 AIO)的真异步 I/O 与 POSIX AIO 的工程边界如何理解?

  • libaio 真异步
  • 与 POSIX AIO 边界
  • 工程取舍

libaio(Linux 原生 AIO)是真异步:io_submit 把 I/O 提交到内核,内核真正异步完成(不阻塞用户线程),用 io_getevents 回收完成事件。工程边界:libaio 要求 O_DIRECT(绕过页缓存,需对齐)、只支持特定文件系统、不支持缓冲 I/O、接口较底层;POSIX AIO 可移植但 Linux 用线程池伪异步。libaio 适合需要可控、真异步且可接受 O_DIRECT 的高性能场景(数据库、存储);不支持缓冲 I/O 是其限制。工程上:Linux 高性能需 O_DIRECT 的异步 I/O 用 libaio,需缓冲/可移植用 io_uring 或 POSIX AIO。

libaio 真异步但需 O_DIRECT、接口底层,POSIX AIO 可移植但伪异步。边界是"是否可接受 O_DIRECT 与 Linux 限定"。

#
★★

38. io_uring 相比 POSIX AIO / libaio 的工程优势?

io_uring 相比 POSIX AIO / libaio 的工程优势是什么?

  • io_uring 优势
  • 对比 POSIX AIO/libaio
  • 工程价值

io_uring 相比 POSIX AIO/libaio 的优势:减少系统调用——用共享内存队列(SQ/CQ)批量提交/回收 I/O,避免每 I/O 一次 syscall;支持缓冲 I/O——libaio 需 O_DIRECT,io_uring 支持缓冲 I/O;支持更多操作——read/write/fsync/网络/定时器/异步事务等;真异步——内核异步完成,不阻塞用户线程;高性能可扩展——大量并发 I/O 高效。工程价值:Linux 5.1+ 的 io_uring 是统一、高效、可扩展的异步 I/O 框架,替代 POSIX AIO(伪异步)与 libaio(限制多)。工程上:Linux 高性能异步 I/O 优先用 io_uring。

io_uring 用共享队列减 syscall、支持缓冲 I/O、多操作、真异步,是比 POSIX AIO/libaio 更优的异步 I/O 方案。

#
★★

39. POSIX AIO 的 lio_listio 批量提交与 libaio io_submit 的工程取舍?

POSIX AIO 的 lio_listio 批量提交与 libaio io_submit 的工程取舍如何理解?

  • lio_listio vs io_submit
  • 批量提交
  • 取舍

lio_listio(POSIX AIO)批量提交——一次提交多个异步 I/O(可 LIO_WAIT/NOWAIT),可移植,但底层 glibc 用线程池伪异步(每请求线程),扩展性差;io_submit(libaio)批量提交——一次提交多个 I/O 到内核,真异步(内核完成),但需 O_DIRECT、仅 Linux、接口底层。取舍:可移植性(lio_listio 可移植 vs io_submit 仅 Linux)与性能(io_submit 真异步高效 vs lio_listio 线程池伪异步)的权衡。工程上:高性能 Linux 批量异步 I/O 用 io_submit(或 io_uring 的批量),需可移植用 lio_listio。

两者都是批量异步提交,但 lio_listio 可移植伪异步、io_submit 真异步仅 Linux。取舍在可移植 vs 性能。

#
★★

40. POSIX AIO 在 -D_POSIX_ASYNCHRONOUS_IO 宏的依赖?

POSIX AIO 在 -D_POSIX_ASYNCHRONOUS_IO 宏的依赖如何理解?

  • POSIX AIO 宏
  • 特性测试宏
  • 编译依赖

POSIX AIO 的使用依赖特性测试宏 POSIX_ASYNCHRONOUS_IO:该宏表示系统/编译环境支持 POSIX 异步 I/O(aio_read 等),程序需在编译时定义(-D_POSIX_ASYNCHRONOUS_IO)或检查(#ifdef)以启用 AIO 功能。这是 POSIX 特性测试宏(feature test macro)机制:声明"程序依赖该 POSIX 特性",编译环境据此提供相应接口/头文件声明。依赖:不定义该宏,某些实现可能不暴露 aio* 接口或行为受限。工程上:使用 POSIX AIO 时定义 _POSIX_ASYNCHRONOUS_IO(或 _XOPEN_SOURCE 等),并检查支持性。

_POSIX_ASYNCHRONOUS_IO 是特性测试宏,声明依赖 POSIX AIO 特性,编译时定义以启用 AIO 接口。

#
★★

41. io_uring 限制,仅在 Linux 5.1+ 与较小生产案例下超越 POSIX AIO 的工程边界如何?

io_uring 限制:仅在 Linux 5.1+ 与较小生产案例下超越 POSIX AIO 的工程边界?

  • io_uring 限制
  • 内核版本
  • 生产案例

io_uring 的限制:仅 Linux 5.1+ 支持(非可移植,BSD/macOS 无);生产案例相对较少(相对 POSIX AIO 的成熟生态),接口/API 仍在演进(5.x 变化),部分特性(如某些操作类型)需较新内核、个别环境有安全/兼容限制(如容器/seccomp 环境禁 io_uring 系统调用)。工程边界:io_uring 在"Linux 5.1+ 且环境允许"的场景超越 POSIX AIO(真异步、高效),但需评估生产成熟度、内核版本、环境兼容性;跨平台/受限环境用 POSIX AIO。工程上:评估内核版本与部署环境后选 io_uring,否则回退 POSIX AIO。

io_uring 仅 Linux 5.1+、API 演进中、生产案例有限,需评估环境兼容再采用,跨平台/受限用 POSIX AIO。

#

42. mprotect 的内存页权限变更与 W^X 边界

mprotect 的内存页权限变更与 W^X 边界如何理解?

  • mprotect
  • 内存页权限
  • W^X 边界

mprotect 修改内存页的访问权限(PROT_READ/PROT_WRITE/PROT_EXEC),改变页表权限位。W^X(Write XOR Execute,即可写则不可执行)是安全原则:内存页不能同时可写又可执行,防止攻击者写入恶意代码后执行(缓冲区溢出注入)。工程上:mprotect 用于实现 JIT 的 W^X(先按 PROT_WRITE 写代码,再 mprotect 改为 PROT_EXEC),或做只读数据保护(如把代码段/常量设为只读)。注意:mprotect 按页(PAGE_SIZE)对齐,权限变更粒度是页。

mprotect 改页表权限,W^X 要求"可写与可执行互斥"。JIT 用"先写后改 exec"实现 W^X,防注入执行。

#

43. UDS 的 SO_PASSCRED 与进程凭据传递

UDS 的 SO_PASSCRED 与进程凭据传递如何理解?

  • SO_PASSCRED
  • 凭据传递
  • 进程验证

SO_PASSCRED(socket 选项)让 Unix domain socket 在接收时附带发送进程的凭据(PID、UID、GID),通过 recvmsg 的辅助数据(SCM_CREDENTIALS)获取。用途:服务端验证发送进程身份(确认是可信进程/用户),实现基于进程凭据的授权/审计。设置:接收端 setsockopt(SO_PASSCRED) 开启,发送端 sendmsg 时可选附带凭据(或内核自动填充)。工程上:UDS 服务端用 SO_PASSCRED 获取客户端进程身份,用于本地安全校验(如仅允许特定用户/进程访问)。

SO_PASSCRED 让 UDS 传递发送方 PID/UID/GID 凭据,服务端据此验证进程身份实现本地授权。

#

44. aio_error/aio_return 的完成检查与 aio_suspend 的等待

aio_error/aio_return 的完成检查与 aio_suspend 的等待如何理解?

  • aio_error/aio_return
  • aio_suspend
  • 异步完成

POSIX AIO 完成检查:aio_error 查询异步 I/O 请求的状态(EINPROGRESS 进行中、0 成功、错误码失败),aio_return 获取返回值(读取/写入的字节数,需在成功后调用);aio_suspend 阻塞等待一个或多个异步 I/O 完成(传 aiocb 列表,超时可选)。用法:提交后轮询 aio_error(非阻塞)或 aio_suspend(阻塞等待完成),完成后 aio_return 取结果。工程上:轮询用 aio_error,等待用 aio_suspend(配合超时),结果用 aio_return,形成异步 I/O 的检查/等待/取结果闭环。

aio_error 查状态、aio_return 取结果、aio_suspend 等待完成。三者配合完成异步 I/O 的收尾。

#

45. timer_create 在 CLOCK_MONOTONIC 的不受 NTP 影响特性

timer_create 在 CLOCK_MONOTONIC 的不受 NTP 影响特性如何理解?

  • CLOCK_MONOTONIC
  • 不受 NTP
  • 定时器

timer_create 用 CLOCK_MONOTONIC 时,定时器不受 NTP 时间调整影响:CLOCK_MONOTONIC 是单调时钟(只增不减,不受系统时间/时钟调整改变),因此用其创建的定时器按"单调时间"递增,NTP 调整系统时间不会导致定时器提前/延后触发。对比 CLOCK_REALTIME 受 NTP/时钟调整影响(可能跳变)。特性价值:相对时长定时(如每 30s 心跳、超时)用 CLOCK_MONOTONIC 保证稳定,不受墙钟调整干扰。工程上:相对定时/超时用 CLOCK_MONOTONIC 定时器,避免 NTP 调整引起定时抖动。

CLOCK_MONOTONIC 不受 NTP 调整,周期/相对定时器用它能稳定触发,避免墙钟跳变干扰。这是单调时钟的核心价值。

#

46. usleep、nanosleep、clock_nanosleep 的精度差异

usleep、nanosleep、clock_nanosleep 的精度差异如何理解?

  • 睡眠函数
  • 精度差异
  • 选择

usleep——微秒级睡眠(旧接口,精度受系统时钟/调度影响,且非 POSIX 推荐);nanosleep——纳秒级睡眠(高精度,但用 CLOCK_REALTIME 的少量实现受时钟调整影响,且异步信号打断返回剩余时间);clock_nanosleep——纳秒级,可指定时钟(CLOCK_MONOTONIC 不受 NTP 调整),支持绝对时间(TIMER_ABSTIME)与相对时间,更精确可控制。精度:三者都受内核调度粒度影响(实际睡眠可能略长于请求),但 clock_nanosleep 用 MONOTONIC+绝对时间最精确稳定。工程上:高精度受控睡眠用 clock_nanosleep(MONOTONIC),常规用 nanosleep,避免 usleep(限制多)。

usleep 旧且受限,nanosleep 纳秒级,clock_nanosleep 更精确(可指定时钟+绝对时间)。高精度用 clock_nanosleep。