Linux进程间通信之IPC (信号量、消息队列、共享内存)

版权声明:随意转载,注明链接地址即可 https://blog.csdn.net/weixin_38812277/article/details/90791185

1、首先要注意一个概念:IPC结构都是内核的结构。也就是说IPC结构由内核维护,对于每个进程都是公共的,不属于某个特定进程。只有这样,IPC结构才能支持它们“进程间通信”的功能。

2、标识符(ID)和键(key)

ID是IPC结构的内部名。内部即在进程内部使用,这样的标识方法是不能支持进程间通信的。

key就是IPC结构的外部名。当多个进程,针对同一个key调用get函数(msgget等),这些进程得到的ID其实是标识了同一个IPC结构。多个进程间就可以通过这个IPC结构通信。

3、优点和缺点

系统范围内起作用,没有访问计数。每一个IPC资源都是持久的,除非被进程显示的释放,否则永远驻留在内存中。与此相比,管道的最后一个访问进程终止的时候,管道也就被删除。对FIFO(命名管道)而言,虽然其名字任然保留在系统中,但是其中的数据已经被删除。

IPC结构在文件系统中没有名字,不能使用read/write访问。为了支持它们不得不增加了十几条全新的系统调用(msgget、semop、shmat等)。我们不能用ls命令见到IPC对象,不能用rm命令删除它们,也不能用chmod命令更改它们的访问权限。于是,就不得不增加新的命令ipcs(1)和ipcrm(1)。

4、信号量

相比于内核信号量:(1)每个IPC信号量都是一个或者多个信号量值的集合。这意味着一个IPC资源可以保护多个独立共享的数据结构。(2)IPC信号量提供一种失效的安全机制,当进程意外退出的时候,进程不能取消对以前信号执行的操作就死亡,IPC信号量都可以恢复为原值。

信号量的使用

#include <sys/sem.h>
int semget(key_t key, int nsems, int flag);

函数说明:nsems是该集合中的信号量数。如果是创建新集合(一般在服务器进程中),则必须指定nsems。如果引用一个现存的集合(一个客户进程),则将nsems指定为0。

int semctl(int semid, int semnum, int cmd, ... /* union semun arg */);

函数说明:semnum指定操作信号量集合中的哪一个信号量。

cmd:【一共九种】

GETVAL       返回成员semnum的semval值。

SETVAL       设置成员semnum的semval值。该值由arg.val指定。

IPC_RMID    从系统中删除该信号量集合。这种删除是立即发生的。仍在使用此信号量集合的其他进程在它们下次试图对此信号量集合进行操作时,将出错返回EIDRM。此命令只能由下列两种进程执行:一种是其有效用户ID等于sem_perm.cuid或sem_perm.uid的进程;另一种是具有超级用户特权的进程。

参考:https://www.cnblogs.com/nufangrensheng/p/3562046.html

【注释】创建和赋初值分开。

int semop(int semid, struct sembuf semoparray[], size_t nops);

函数说明:参数nops规定该数组(semoparray)中操作的数量(元素数)。【该函数具有原子性】

5、消息队列:【新的应用程序不应当再使用】

msgget用于创建一个新队列或打开一个现存的队列msgsnd将新消息添加到队列尾端。每个消息包含一个正长整型类型字段,一个非负长度以及实际数据字节(对应于长度),所有这些都在将消息添加到队列时,传送给msgsnd。msgrcv用于从队列中取消息。我们并不一定要以先进先出次序取消息,也可以按消息的类型字段取消息。

消息:每个消息都由三部分组成,它们是:正长整型类型字段、非负长度(nbytes)以及实际数据字节(对应于长度)。消息总是放在队列尾端。

消息队列的使用:

创建一个消息队列:

#include <sys/msg.h>
int msgget(key_t key, int flag);
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
int msgsnd(int msqid, const void *ptr, size_t nbytes, int flag);
ssize_t msgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag);

共享内存:【最有用的IPC机制】          区别于mmap产生的内存映射(也可以用做进程间通信)

共享内存需要用户自己实现同步。

#include <sys/shm.h>
int shmget(key_t key, size_t size, int flag);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
void *shmat(int shmid, const void *addr, int flag);
int shmdt(void *addr);

【补充】父子进程通信可以使用匿名存储映射,子进继承父进程的地址空间。

参考:https://www.cnblogs.com/nufangrensheng/p/3562046.html

猜你喜欢

转载自blog.csdn.net/weixin_38812277/article/details/90791185