管道

匿名管道

概述

参数说明:

返回值:

相关函数


Note

  • 读写操作默认是阻塞的

  • 内核缓冲区大小通常为64KB

  • 必须正确关闭不使用的端

  • 写入已关闭读端的管道会产生SIGPIPE

示例

命名管道

概述

参数说明:

返回值:

相关函数

常用flags


Note

  • 创建时需要设置合适的权限

  • 打开FIFO时可能阻塞,直到另一端也打开

  • 使用完毕后应删除FIFO文件

  • 多个进程可以同时访问同一个FIFO

示例

示例代码:读进程

信号

概述

Note

  1. 信号可能在任何时候到达

  2. 同类型信号在处理期间再次到达会被丢弃

  3. 信号可能中断系统调用

  4. 需要小心处理信号处理函数中的共享数据

  5. 某些信号在不同系统上行为可能不同

常用信号类型

信号名信号值默认动作说明
SIGINT2终止中断信号(Ctrl+C)
SIGQUIT3终止+核心转储退出信号(Ctrl+)
SIGKILL9终止强制杀死(不可捕获)
SIGTERM15终止终止信号(可捕获)
SIGCHLD17忽略子进程状态改变
SIGUSR110终止用户自定义信号1
SIGUSR212终止用户自定义信号2
SIGALRM14终止定时器信号

常用函数

1.signal() 函数

参数说明:

返回值:


2. sigaction() 函数

参数说明:


3. kill() 函数

参数说明:


4. raise() 函数

功能: 向当前进程发送信号,等价于kill(getpid(), sig)

示例

 

消息队列

消息队列是一种重要的进程间通信机制,允许进程通过消息进行异步通信。Linux提供了两种消息队列实现:System V消息队列和POSIX消息队列。

消息队列提供了可靠的异步通信机制,特别适合生产者-消费者模式的应用场景。

System V消息队列

常用函数

  1. msgget() - 创建或获取消息队列

    • key: 消息队列的键值(通常使用ftok()生成)

    • msgflg: 权限标志和创建标志

    • 返回值: 消息队列标识符

  2. msgsnd() - 发送消息

    • msqid: 消息队列标识符

    • msgp: 指向消息结构的指针

    • msgsz: 消息数据的大小

    • msgflg: 控制标志

  3. msgrcv() - 接收消息

    • msgtyp: 消息类型(0表示接收任意类型)

  4. msgctl() - 控制消息队列

    • cmd: 控制命令(如IPC_RMID删除队列)

示例

发送端:

接收端:

POSIX消息队列

特点: 更现代的接口,支持异步通知

常用函数

  1. mq_open() - 打开或创建消息队列

    • name: 消息队列名称(以"/"开头)

    • oflag: 打开标志(O_RDONLY, O_WRONLY, O_RDWR等)

  2. mq_send() - 发送消息

    • msg_prio: 消息优先级(0-31,数值越大优先级越高)

  3. mq_receive() - 接收消息

  4. mq_close() - 关闭消息队列

  5. mq_unlink() - 删除消息队列

示例

发送端:

接收端:

共享内存

共享内存是最快的进程间通信方式,允许多个进程直接访问同一块物理内存区域。

Note

共享内存本身不提供同步机制,需要配合其他IPC方式:

  1. 信号量: 控制对共享内存的访问

  2. 互斥锁: 保护临界区

  3. 条件变量: 等待特定条件

  4. 文件锁: 基于文件的锁机制

System V共享内存

常用函数

  1. shmget() - 创建或获取共享内存段

    • key: 共享内存的键值(通常使用ftok()生成)

    • size: 共享内存段的大小(字节)

    • shmflg: 权限标志和创建标志

    • 返回值: 共享内存标识符

  2. shmat() - 连接共享内存段到进程地址空间

    • shmid: 共享内存标识符

    • shmaddr: 指定连接地址(通常为NULL,让系统选择)

    • shmflg: 连接标志(如SHM_RDONLY只读)

    • 返回值: 共享内存段的起始地址

  3. shmdt() - 断开共享内存段连接

    • shmaddr: 要断开的共享内存地址

  4. shmctl() - 控制共享内存段

    • cmd: 控制命令(如IPC_RMID删除共享内存)

示例

写进程:

读进程:

POSIX共享内存

常用函数

  1. shm_open() - 创建或打开共享内存对象

    • name: 共享内存对象名称(以"/"开头)

    • oflag: 打开标志(O_CREAT, O_RDWR等)

    • mode: 权限模式

    • 返回值: 文件描述符

  2. ftruncate() - 设置共享内存对象大小

  3. mmap() - 将共享内存映射到进程地址空间

    • prot: 内存保护标志(PROT_READ, PROT_WRITE等)

    • flags: 映射标志(MAP_SHARED等)

  4. munmap() - 取消内存映射

  5. shm_unlink() - 删除共享内存对象

示例

写进程:

读进程:

 

信号量

信号量是一种用于进程同步的重要机制,主要用于控制对共享资源的访问。

System V信号量

常用函数

  1. semget() - 创建或获取信号量集

    • key: 信号量集的键值(通常使用ftok()生成)

    • nsems: 信号量集中信号量的数量

    • semflg: 权限标志和创建标志

    • 返回值: 信号量集标识符

  2. semop() - 对信号量进行操作

    • semid: 信号量集标识符

    • sops: 指向操作数组的指针

    • nsops: 操作数量

  3. semctl() - 控制信号量集

    • semnum: 信号量编号

    • cmd: 控制命令(如SETVAL设置值、IPC_RMID删除)

sembuf结构体

示例

生产者-消费者模型

消费者:

POSIX信号量

常用函数

  1. sem_open() - 创建或打开命名信号量

    • name: 信号量名称(以"/"开头)

    • oflag: 打开标志(O_CREAT等)

    • value: 初始值

  2. sem_wait() - 等待信号量(P操作)

  3. sem_trywait() - 非阻塞等待

  4. sem_post() - 释放信号量(V操作)

  5. sem_close() - 关闭信号量

  6. sem_unlink() - 删除命名信号量

示例

生产者:

消费者:

信号量操作类型

P操作(等待/减少)


V操作(信号/增加)

套接字

Unix域套接字

概述与常用函数

Unix域套接字(Unix Domain Socket)是一种高效的本地进程间通信机制,它使用文件系统路径作为地址,仅在本地机器上工作,性能优于网络套接字。

常用函数

  1. socket() - 创建套接字

    • domain: AF_UNIX(Unix域)

    • type: SOCK_STREAMSOCK_DGRAM

    • protocol: 通常为0

  2. bind() - 绑定地址

  3. listen() - 监听连接(仅SOCK_STREAM

  4. accept() - 接受连接(仅SOCK_STREAM

  5. connect() - 连接到服务器

  6. send()/recv() - 发送/接收数据

  7. sendto()/recvfrom() - 数据报发送/接收

示例

服务器端

客户端

网络套接字

内存映射

内存映射(Memory Mapping)是一种高效的进程间通信机制,它将文件或设备映射到进程的虚拟地址空间,使得多个进程可以通过共享内存的方式访问同一个文件。

常用函数

mmap() - 创建内存映射

参数说明:

返回值:


munmap() - 取消内存映射

参数说明:

返回值:


msync() - 同步映射区域到文件

mprotect() - 修改内存保护属性

madvise() - 提供内存使用建议

mmap原理

虚拟内存管理

  1. 页表映射

    • mmap在进程的虚拟地址空间中分配一段连续的虚拟地址

    • 建立虚拟地址到物理页面的映射关系

    • 通过页表(Page Table)管理这种映射

  2. 延迟加载(Lazy Loading)

    • mmap调用时并不立即加载文件内容到内存

    • 只有当进程访问某个页面时才触发页面错误(Page Fault)

    • 内核此时才从文件中读取对应页面到物理内存

  3. 写时复制(Copy-on-Write)

    • 对于MAP_PRIVATE映射,多个进程可以共享同一物理页面

    • 当某个进程尝试写入时,内核创建页面的私有副本

    • 实现了内存的高效利用

内核实现机制

  1. VMA(Virtual Memory Area)

    • 内核为每个映射创建VMA结构

    • 记录映射的起始地址、长度、权限、文件信息等

    • 链接到进程的内存描述符中

  2. 页面缓存(Page Cache)

    • 文件页面在内存中的缓存

    • 多个进程映射同一文件时共享相同的物理页面

    • 提高了内存利用率和访问效率

  3. 脏页管理

    • 跟踪被修改的页面(脏页)

    • 定期或在特定条件下将脏页写回文件

    • 确保数据一致性

内存映射与共享内存的区别

内存映射(mmap)是一种通用的内存管理机制, 可以映射文件、设备或匿名内存, 是底层的系统调用。

POSIX共享内存是一种专门的IPC机制,是基于mmap实现的高层抽象,专门用于进程间通信。

普通文件映射存储在普通文件系统,共享内存存储在专用的共享内存文件系统。

可以这样理解:POSIX共享内存是基于mmap实现的专门IPC机制,而mmap是更通用的内存管理工具。就像汽车和交通工具的关系——汽车是基于交通工具概念实现的专门载具,但交通工具包含更广泛的概念。

特性内存映射(mmap)POSIX共享内存
底层实现直接系统调用基于mmap + shm_open
命名方式文件路径POSIX名称(/name)
存储位置任意文件系统专用共享内存文件系统
生命周期跟随文件独立于进程
权限管理文件系统权限POSIX权限
可移植性平台相关POSIX标准
用途通用内存管理专门IPC

示例

写进程

读进程

文件锁

文件锁是一种通过对文件加锁来实现进程同步和互斥访问的IPC机制。它可以防止多个进程同时修改同一个文件,确保数据的一致性。

锁的类型

锁的模式

常用函数

1. fcntl() 函数

参数说明:

flock结构体:

2. flock() 函数

参数说明:

示例

eventfd

eventfd 是Linux内核提供的一种轻量级的事件通知机制,用于进程间或线程间的同步和通信。它创建一个特殊的文件描述符,可以用于事件计数和通知。

概述

eventfd 是一个内核对象,通过文件描述符进行访问,其内部维护一个64位无符号整数计数器,支持读写操作来进行事件通知和同步。可以与epoll、select、poll等IO多路复用机制配合使用

eventfd系统调用返回的是文件描述符,该文件描述符可以读、写、监听。

  • 使用eventfd时,内核中会维护一个计数器

  • 对eventfd执行以下函数

read函数:如果计数器的值不为0时,读取成功,获得到该值;如果计数器的值为0,非阻塞模式时,会直接返回失败,并把error置为EINVAL;如果为阻塞模式,一直会阻塞到A为非0为止。 write函数:将缓冲区写入的8字节整型值加到内核计数器上(累加效果),即会增加8字节的整数在计数器上,如果其值达到0xfffffffffffffffe时,就会阻塞(在阻塞模式下),直到计数器的值被read。

通过对eventfd函数返回的文件描述符进行通信。一个进程或者线程A执行read操作,如果内核计数器的值为0,并且是阻塞模式,那么A就会阻塞;另外一个进程或者线程B执行write操作,就会向内核计数器写,那么阻塞的A发现内核计数器的值不为0,就会被触发,那么两个进程或者线程A与B就达到通信的目的了(通知)

常用函数

1. eventfd() 函数

参数说明:

返回值:

2. 读写操作

工作模式

1. 计数器模式(默认)

2. 信号量模式(EFD_SEMAPHORE)

示例

定时器timerfd

timerfd 是Linux内核提供的一种基于文件描述符的定时器机制。它将定时器抽象为文件描述符,可以与epoll、select、poll等IO多路复用机制集成,实现高效的异步定时器处理。

Note

timerfd是一种时间同步和事件通知机制 ,而不是传统意义上的数据传输IPC。

常用函数

1. timerfd_create() 函数

参数说明:

2. timerfd_settime() 函数

参数说明:

3. timerfd_gettime() 函数

4. itimerspec 结构体

示例