您的位置:首页 > 其它

IPC通信之消息队列、信号量和共享内存

2014-12-02 23:23 120 查看
有三种IPC我们称作XSI IPC,即消息队列,信号量以及共享存储器。XSI IPC源自System V的IPC功能。由于XSI IPC不使用文件系统的命名空间,而是构造了它们自己的名字空间,为此常常受到批评。

相似之处:每个内核中的IPC结构都用一个非负整数的标识符加以引用。例如对一个消息队列发送或取消息,只需要知道其队列标识符。与文件标识符不同,IPC标识符不是小的整数,当一个IPC结构被创建,以后又被删除时,与这种结构相关的标识符连续加1,直至达到一个整形数的最大正值,然后又回转到0.

标识符是IPC对象的内部名,为使多个合作进程能够在同一IPC对象上会合,需要提供一个外部名方案。为此使用了key,每个IPC对象都与一个key相关连,于是key就用作为该队向的外部名。

优缺点:IPC结构是在系统范围内起作用的,没有访问计数。例如,如果进程创建了一个消息队列,在该队列中放入了几则消息,然后终止,但是该消息队列及其内容并不会被删除,它们余留在系统中直至出现下述情况:由某个进程调用msgrcv或msgctl读取消息或删除消息队列,或某个进程执行ipcrm命令删除消息队列,或由正在再启动的系统删除消息队列,将此与管道相比,当最后一个访问管道的进程终止时,管道就被完全地删除了。对于FIFO而言,虽然当最后一个引用FIFO进程终止时其名字仍保留在系统中,直至显式地删除它,但是留在FIFO中的数据却在此时被全部删除,于是也就徒有虚名了。

XSI IPC的另一个问题是这些IPC结构在文件系统中没有名字,我们不能使用那些使用文件系统的函数来访问它们或修改他们的属性。为了支持它们不得不增加了十几条全新的系统调用(msgget,semop,shmat).我们不能用ls命令见到IPC对象,不能用rm命令删除他们,不能用chmod命令修改它们的访问权限。于是就不得不增加新的命令ipcs和ipcrm.

因为这些IPC不是用文件描述符,所以不能对他们使用多路复用I/O函数:epoll/select/poll(这是个致命伤,因为现在很多高性能的服务器编程模型都是使用epoll的,所以这三种通信机制也只能在一些简单的场合使用了)。这就使得难于一次使用多个IPC结构,以及在文件或设备I/O中使用IPC结构。例如,没有某种形式的忙--等待循环,就不能使一个服务器进程等待将要放在两个消息队列任一个中的消息。

消息队列的一个其它优点是:可靠,流是可以控制的,面向记录,以非先进先出方式处理。

相关API:

信号量:

它是一个计数器,用于多进程对共享内存数据对象的访问。

#include<sys/sem.h>

int semget(key_t key,int num_sems,int sem_flgs);

int semctl(int sem_id,int sem_num,int command...);

int semop(int sem_id,struct sembuf *sem_ops,size_t num_sem_ops);

共享内存:

允许两个或更多的进程共享一个给定的存储区,通常,信号量被用来实现对共享存储访问的同步

#include<sys/shm.h>

int shmget(key_t key,size_t size,int shmflag);

void *shmat(int shm_id,const void *shm_addr,int shm_flag);

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

int shmdt(const void *shm_addr);

消息队列:

提供从一个进程向另一个进程发送一个数据块的方法(一般新的应用程序不推荐使用)

#include<sys/msg.h>

int msgget(key_t key,int msgflg);

int msgctl(int magid,int cmd,struct msgid_ds *buf);

int msgsnd(int msgid,void *msg_ptr,size_t msg_sz,int msgflag);

int msgrcv(int msgid,void *msg_ptr,size_t msg_sz,long int msg_type,int msgflag);

示例

打印不同类型数据存放的位置

#include <stdio.h>
#include <sys/shm.h>

#define	ARRAY_SIZE	40000
#define	MALLOC_SIZE	100000
#define	SHM_SIZE	100000
#define	SHM_MODE	0600	/* user read/write */

char	array[ARRAY_SIZE];	/* uninitialized data = bss */

int
main(void)
{
int		shmid;
char	*ptr, *shmptr;

printf("array[] from %p to %p\n", (void *)&array[0],
(void *)&array[ARRAY_SIZE]);
printf("stack around %p\n", (void *)&shmid);

if ((ptr = malloc(MALLOC_SIZE)) == NULL)
printf("malloc error");
printf("malloced from %p to %p\n", (void *)ptr,
(void *)ptr+MALLOC_SIZE);

if ((shmid = shmget(IPC_PRIVATE, SHM_SIZE, SHM_MODE)) < 0)
printf("shmget error");
if ((shmptr = shmat(shmid, 0, 0)) == (void *)-1)
printf("shmat error");
printf("shared memory attached from %p to %p\n", (void *)shmptr,
(void *)shmptr+SHM_SIZE);

if (shmctl(shmid, IPC_RMID, 0) < 0)
printf("shmctl error");

exit(0);
}



mmap函数可将一个文件的若干部分映射至进程地址空间。这个概念上类似于用shmat函数连接一个共享存储段。两者之间的区别是,用mmap映射的存储段是与文件关联的,而XSI共享存储段并无这种关联。

更详细参考:

Linux进程间通信——使用共享内存

Linux进程间通信——使用消息队列


Linux进程间通信——使用信号量

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: