IO进程 day07
11. 进程间通信机制
11.3. 有名管道
无名管道和有名管道的区别
无名管道 | 有名管道 | |
---|---|---|
应用场景 | 具有亲缘关系进程 | 不相关的进程 |
相同点 | 可以当作一个特殊的文件,通过文件IO进行操作 遵循先进先出的原则,不能使用lseek操作 数据存储在内核空间 | 与无名管道相同 |
不同点 | 有固定的读端和写端 | 文件系统中存在文件 |
读写 | pipe 直接进行读写 | mkfifo 先打开才能读写 |
11.4. 信号
信号的概念
- 信号是在软件层上对中断机制的模拟,是一种异步的通信方式
- 信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以通知用户空间进程发生了哪些系统事件
- 如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递给它,如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程
信号的分类
命令:kill -l
查看信号
- 不可靠信号,又叫非实时信号,不支持排队,信号可能会丢失,比如发送多次相同的信号,进程只能收到一次,信号值取值区间为1-31
- 可靠信号,又叫实时信号,支持排队,信号不会丢失,发多少次,就收到多少次,信号值取值区间为32-64
特殊信号
信号编号 | 宏名 | 功能 | 备注 |
---|---|---|---|
2) | SIGINT | 结束进程 | 快捷键ctrl+c |
3) | SIGQUIT | 结束进程 | 快捷键ctrl+\ |
20) | SIGTSTP | 暂停进程 | 快捷键ctrl+z |
17) | SIGCHLD | 子进程状态发生变化时 给父进程发送这个信号 | |
14) | SIGALRM | 结束进程 | 闹钟信号 |
9) | SIGKILL | 结束进程 | 不能被忽略不能被捕捉 |
19 ) | SIGSTOP | 结束进程 | 不能被忽略不能被捕捉 |
10) | SIGUSR1 | 未定义功能 | 用户可以自定义 |
12) | SIGUSR2 | 未定义功能 | 用户可以自定义 |
信号的处理方式
- 忽略信号: 当信号到来时对他进行忽略
- 捕捉信号: 当信号到来时对信号进行处理,执行自定义的操作
- 执行缺省(默认)操作: 执行信号默认的功能
信号产生的方式
- 对于前台进程
- 系统异常
- 系统状态变化
- 终端kill命令或者程序中kill函数
函数接口
kill & raise - 发送信号
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
int raise(int sig);
功能:发信号
kill
发送信号
raise
给自己发信号
参数:
pid_t pid
进程号
int sig
信号
返回值:成功返回0,失败返回EOF
alarm - 定时
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
功能:在进程中定时操作
参数:unsigned int seconds
定时,单位是秒
返回值:上次设定闹钟的剩余时间
注意
第一次调用:返回0
第二次调用:第一次闹钟调用完,到现在调用剩下的时间吗,同时以第二次调用设定的时间为准
signal - 信号处理
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
注意
typedef int INT;
重定义:数据类型 变量名
函数指针:void (*sighandler_t)(int) == void (*)(int) sighandler_t
重定义:typedef void (*)(int) sighandler_t == typedef void (*sighandler_t)(int)
sighandler_t handler == void (*handler)(int) 该参数是一个函数指针,传参需要一个函数名
功能:对信号进行处理
参数:
int signum
信号编号
sighandler_t handler
函数指针,信号的处理方式
信号 | 操作 |
---|---|
SIG_IGN | 忽略信号 |
SIG_DFL | 默认操作 |
自定义函数 | 调用函数 |
返回值:成功返回设置处理方式之前的处理方式,失败返回EOF
11.5. 共享内存
概念
共享内存是通过虚拟内存管理机制将物理内存映射到多个进程的虚拟地址空间中。共享内存的虚拟地址范围是动态分配的,一般是在内存映射区,但具体位置由内核动态分配。
特点
- 共享内存是一种最为高效的进程间通信方式,进程可以直接读写物理内存,而不需要任何数据的拷贝,从而大大提高的效率
- 由于多个进程共享一段内存,因此也需要依靠某种同步机制
流程
- 创建 key ftok
- 创建共享内存 shmget(share memory)
命令查看:ipcs -m
- 映射 shmat
- 直接读写共享内存 read/write
- 取消映射 shmdt
- 删除共享内存 shmctl
ftok
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
功能:生成唯一的 key
参数:
const char *pathname
文件名,只获取inode号
int proj_id
低8位,传一个字符即可
返回值:成功返回生成的key,失败返回EOF
shmget
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
功能:创建或打开共享内存
参数:
key_t key
关键字
size_t size
共享内存的大小
int shmflg
直接使用:IPC_CREAT | IPC_EXCL | 0777
返回值:成功返回共享内存ID(shmid),失败返回EOF
注意
- 创建成功了之后,打开共享内存,重新获取shmid
shmid = shmget(key, 64, IPC_CREAT | IPC_EXCL | 0777);
if (shmid == EOF)
{
if (errno == EEXIST)
// 创建成功了之后,打开共享内存,重新获取shmid
shmid = shmget(key, 64, 0777);
else
{
perror("shmget err");
return EOF;
}
}
shmat
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:地址映射
参数:
int shmid
共享内存标识,shmid
const void *shmaddr
映射方式,一般为NULL
int shmflg
读写权限
返回值:成功返回映射后的地址,失败返回(void *)EOF
注意
- 使用方式与
malloc
相同,需要强转 - 读写权限:
0
:可读可写
SHM_RDONLY
:只读
shmdt
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
功能:取消映射
参数:const void *shmaddr
要取消的地址
返回值:成功返回0,失败返回EOF
shmctl
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid,int cmd,struct shmid_ds *buf);
成功:对共享内存进行各种操作,主要是删除共享内存
参数:
int shmid
共享内存id
int cmd
对共享内存的操作
struct shmid_ds *buf
结构体指针
返回值:成功返回0,失败返回EOF
注意
- 参数:
操作 | 功能 | 结构体指针 |
---|---|---|
IPC_STAT | 获得shmid属性信息 | 存放信息 |
IPC_SET | 设置shmid属性信息 | 设置的属性 |
IPC_RMID | 删除共享内存 | NULL |
操作命令
ipcs -m #查看共享内存
ipcs -m [shmid] #删除共享内存