IPC
-
匿名管道 ps -ef | grep <key>
用完了就销毁了
-
命名管道
mkfifo <pipename> # 此时命令不会结束 echo 'content' > <pipename> # 在另一个tty执行 cat < <pipename>
-
消息队列
ipcmk -Q ipcs -q ipcrm -Q
发送消息主要调用 msgsnd 函数
收消息主要调用 msgrcv 函数
-
共享内存模型
ipcmk -M ipcs -m ipcrm -M
通过 shmat 函数将这个内存加载到自己的虚拟地址空间
如果共享内存使用完毕,可以通过 shmdt 解除绑定
通过 shmctl,将 cmd 设置为 IPC_RMID,从而删除这个共享内存对象
-
信号量
ipcmk -S ipcs -s ipcrm -S
- P 操作 申请资源操作
- V操作 归还资源操作
通过semget创建一个信号量
通过semctl初始化信号量的总的资源数量
用 semop 进行P,V操作
-
信号
# 查看所有信号 kill -l # 查看信号对应的事件 man 7 signal
信号
用户进程对信号的处理方式
-
执行默认操作
- Term终止进程
- Core(Core Dump) 终止进程后,通过 Core Dump 将当前进程的运行状态保存在文件里面
-
捕获信号
为信号定义一个信号处理函数。当信号发生时,我们就执行相应的信号处理函数。
-
忽略信号
不做任何处理。
SIGKILL 和 SIGSTOP 不能被忽略
信号注册
信号发送
- 信号的发送通过 kill/tkill/tgkill/rt_sigqueueinfo 函数执行
- 最终通过 __send_signal, 将这个信号添加到对应 进程/线程 的信号待处理链表中
- < 32 为不可靠信号, 待处理列表中存在该信号, 则会自动忽略
- >= 32 为可靠信号, 同一个信号会被添加到信号队列中
信号执行
- 信号的处理会在系统调用或中断处理结束返回用户空间的时机通过 exit_to_usermode_loop 中的 do_signal 执行
- 修改用户函数栈, 插入我们构建的信号处理函数的栈帧 rt_sigframe, 并且将原来的函数栈信息保存在 uc_mcontext 中
- 信号处理函数执行结束之后, 会通过系统调用 rt_sigreturn 恢复之前用户态栈
-
管道
- 匿名管道: 只能在管道创建进程及其后代之间通信
- 通过 pipe 系统调用创建
- inode 由特殊的文件系统 pipefs 创建
- inode 关联的 fos 为 pipefifo_fops
- 命名管道: 通过管道文件名, 可以在任意进程之间通信
- 通过 mkfifo Glibc 库函数创建
- 内部调用 mknodat 系统调用
- inode 由普通文件系统创建, 真实存在于磁盘中
- inode 关联的 fops 与匿名管道一致, 为 pipefifo_fops
匿名管道,其实就是内核里面的一串缓存
IPC
- 无论是共享内存还是信号量,创建与初始化都遵循同样流程,通过 ftok 得到 key,通过 xxxget 创建对象并生成 id;
- 生产者和消费者都通过 shmat 将共享内存映射到各自的内存空间,在不同的进程里面映射的位置不同;
- 为了访问共享内存,需要信号量进行保护,信号量需要通过 semctl 初始化为某个值;
- 接下来生产者和消费者要通过 semop(-1) 来竞争信号量,如果生产者抢到信号量则写入,然后通过 semop(+1) 释放信号量,如果消费者抢到信号量则读出,然后通过 semop(+1) 释放信号量;
- 共享内存使用完毕,可以通过 shmdt 来解除映射。