Linux 进程间通信(IPC):信号、共享内存

1.无名管道

1.管道本质:

内核空间中的一段缓冲区,遵循先进先出特点。

无名管道的:读端:pipefd[0]

写端:pipefd[1]

读写端不能交换。

无名管道默认大小:65536bytes = 64K

2.管道的特性:

  1. 写阻塞:读端和写端都存在,向管道中写数据,当管道满时,发生写阻塞。

  2. 读阻塞:读端和写端都存在,从管道中读数据,若管道为空,则发生读阻塞。

  3. 读返回0:当写端关闭,从管道中读数据,若管道中有数据,则读到数据;

若管道中没有数据,read则返回0,不再阻塞。

  1. 管道破裂:读端关闭,向管道中写入数据,发生管道破裂(异常)

2.有名管道本质:

内核空间的一段缓冲区,但这块缓冲区和一个管道文件相关联

3.信号

信号:

实现进程间的通知机制

实现进程间的异步通信

异步通信:接收方不知道什么时间发送方会发送数据

1.系统支持的信号

kill -l 查看

2) SIGINT:ctrl + c

让一个进程被打断

3) SIGQUIT:ctrl + \

让一个进程结束

9) SIGKILL:

强制让一个进程结束

11)SIGSEGV:

让一个进程结束(段错误)

13)SIGPIPE:

让一个进程结束(管道破裂)

14)SIGALRM:

让一个进程结束(定时时间到达)

17)SIGCHLD:

子进程结束时发送给父进程

18)SIGCONT:

让停止态的进程继续执行

19)SIGSTOP:

让运行态的进程进入停止态(暂停)强制停止

20)SIGTSTP:

ctrl + z 让进程进入暂停态,后台进程

来自终端的停止信号

  1. SIGUSR1

  2. SIGUSR2

用户可自定义的信号

管理员信号

  1. SIGKILL

  2. SIGSTOP

管理员信号:只能按照默认方式处理,不能够被忽略和捕获。

2.信号处理流程

信号处理方式:

1.缺省:按照默认方式进行处理

2.忽略:不处理

3.捕获:以自定义方式处理

signal函数

sighandler_t signal(int signum, sighandler_t handler);

功能:设置信号的处理方式(注册一个信号)

参数:

signum:要处理的信号编号

handler:

SIG_IGN:忽略方式处理该信号

SIG_DFL:缺省方式处理

函数地址:捕获方式处理

返回值:

失败:NULL

自定义方式:返回自定义函数入口

void (*sighandler_t)(int signum);

sighandler_t:执行信号任务处理函数的入口

参数:

signum:触发该任务函数的信号

信号未被注册,则按照默认方式处理

信号只需注册一次,并且应该尽早注册

每次接收到信号都会触发一次信号函数

3.发送信号

  1. kill命令

2.kill()

int kill(pid_t pid, int sig)

功能:给指定的进程发送一个信号

参数: pid:接收信号的进程PID

sig:信号的编号

返回值: 成功:0; 失败:-1;

3.子进程结束时,会发送SIGCHLD信号给父进程 子进程空间

异步回收:通过子进程发送的SIGCHLD信号实现。

  1. int raIse(int sig)

功能:给自己所在进程发信号

5.unsigned int alarm(unsigned int seconds);

功能:设置一个闹钟不当闹钟时间到达时,向自己所在的进程发送一个SIGALRM

参数:

seconds:设置的闹钟的定时时间

返回值: 成功返回上次设定剩余的时间 ,上次未设定则返回0

6.pause()

功能:让一个进程进入可唤醒的休眠状态

注意:paues可以被一个可捕获的信号唤醒(9,19号信号不可被捕获)

4.共享内存

共享内存:进程间效率最高的通信方式

1.通信原理

使用内核空间中内存区域共享

使用内存映射技术,减少的数据的反复拷贝,提高了通信效率

2.共享内存操作流程

IPC对象

1.创建IPC Key:key t ftok(const char *pathname, int proj_id)

功能:创建一个IPC Key

参数:pathname 路径

proj_id: 工程ID

注意:两个进程在创建KEY时必须使用相同的参数

返回值:

成功:IPC key

失败:-1

2.创建共享内存:int shmget(key_t key, size t size, int shmflg);

功能:创建一个共享内存

参数:

key:IPC key

size:共享内存的大小

会被扩展成PAGE_SIZE(4096bytes)的整数倍

shmflg:

IPC_CREAT | 0664

返回值:

成功:共享内存的ID

失败:-1

3.建立共享内存段与用户空间的的内存映射:

void *shmat(int shmid, const void *shmaddr, int shmflg);

功能:建立共享内存内存映射

参数:

shmid :共享内存id

shmaddr:映射的用户空间首地址

NULL:让操作系统分配

shmflg:

SHM_RDONLY:只读

!SHM_RDONLY:可读可写

返回值:

成功:映射的用户空间首地址

失败:(void *) -1

4.向共享内存写入数据(通过用户空间首地址)

5.解除映射关系:int shmdt(const void *shmaddr);

功能:解除内存映射关系

参数:

shmaddr:要解除的用户空间首地址

返回值:

成功:0

失败:-1

6.删除共享内存:int shmctl(int shmid, int cmd, struct shmid ds *buf);

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

功能:操作共享内存

参数:

shmid:要操作的共享内存id

cmd:要执行的操作指令

IPC_RMID:删除操作

buf:设置的参数

返回值:

成功:0

失败:-1

ipcs -a 查看内核中的IPC对象

ipcrm -s 删除信号量集

ipcrm -m 删除共享内存

ipcrm -m shmid

ipcrm -M shmkey

5.信号量集

实现进程间同步

6.消息队列

和管道类似,有同步效果

增加数据的等级(优先级:优先级数据越小,优先级越高)