首页 > 其他 > 详细

linux进程通信之共享内存

时间:2014-03-10 17:51:54      阅读:579      评论:0      收藏:0      [点我收藏+]
共享存储允许两个或多个进程共享同一给定的存储区。因为数据不需要在客户进程和服务器进程之间复制,所以这是最快的一种IPC。使用共享存储时要注意多个进程之间对同一给定存储区的同步访问.


内核为每个共享存储段设置了一个shmid_ds结构

struct shmid_ds{
    struct ipc_perm shm_perm;           /*操作权限*/
    int shm_segsz;                      /*段的大小(以字节为单位)*/
    time_t shm_atime;                   /*最后一个进程附加到该段的时间*/
    time_t shm_dtime;                   /*最后一个进程离开该段的时间*/
    time_t shm_ctime;                   /*最后一个进程修改该段的时间*/
    unsigned short shm_cpid;            /*创建该段进程的pid*/
    unsigned short shm_lpid;            /*在该段上操作的最后1个进程的pid*/
    short shm_nattch;                   /*当前附加到该段的进程的个数*/
    unsigned short shm_npages;          /*段的大小(以页为单位)*/
    unsigned long *shm_pages;           /*指向frames->SHMMAX的指针数组*/
    struct vm_area_struct *attaches;    /*对共享段的描述*/
};


在IPC中,我们经常用用key_t的值来创建或者打开信号量,共享内存和消息队列。通常情况下,该id值通过ftok函数得到

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
返回值:成功返回key_t值,失败返回-1

1)pathname一定要在系统中存在并且进程能够访问的,一般使用当前目录,如:
key_t key;
key = ftok(".", 1); 这样就是将fname设为当前目录。
2)proj_id是一个1-255之间的一个整数值,典型的值是一个ASCII值。


调用函数shmget获得一个共享存储表示符

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
返回值:成功返回共享存储ID,出错返回-1
参数size是共享存储段的长度.通常将其向上取为系统页长的整数倍。如果创建一个新段必须指定size,引用现存的段则size指定为0
注意:若指定的size值并非系统页长的整数倍,那么最后一页的余下部分是不可以使用的。

shmflg参数:
0:取共享内存标识符,若不存在则函数会报错
IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符
IPC_CREAT|IPC_EXCL:如果内核中不存在键值 与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存则报错
用户读    0400
用户写    0200
组读        0040
组写        0020
其他读    0004
其他写    0002


一旦创建了一个共享存储段,进程就可调用shmat将其链接到它的地址空间,shmdt取消链接

#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
返回值:成功返回共享内存地址,出错返回-1
int shmdt(const void *shmaddr);
返回值:成功返回0,出错返回-1
若addr为0,则由内核选择第一个可用地址
若addr非0,并且没有指定SHM_RND,则此段链接到addr所指定的地址上
shmflg参数若指定SHM_RDONLY位,则以只读方式链接,否则以读写方式链接


shmctl函数对共享存储段执行多种操作

#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
返回值:成功返回0,出错返回-1
cmd参数指定下列5种命令中的一种,使其在shmid指定的段上执行

IPC_STAT    取此段的shmid_ds结构,并放在buf指向的结构中
IPC_SET     按buf指向的结构中的值设置与此段相关结构中下列三个段:shm_perm.uid shm_perm.gid shm_perm.mode
IPC_RMID	从系统中删除共享存储段
Linux和Solaris提供了另外两种命令,此命令只能由超级用户执行
SHM_LOCK    将共享存储段锁在内存中。
SHM_UNLOCK  解锁共享存储段。

多进程通信简单示例:


进程A

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/shm.h>
#include <sys/ipc.h>

key_t key;
int   shmid;
int   *p;
int   i=0;

void deal(int s)
{
	if(s==SIGINT)
	{
		//4.卸载共享内存shmdt
		shmdt(p);
		//5.删除共享内存shctl
		shmctl(shmid,IPC_RMID,0);
		exit(0);
	}
}

main()
{	
	signal(SIGINT,deal);
	//1.创建共享内存shmget
	key=ftok(".",255);
	if(key==-1) printf("ftok error:%m\n"),exit(-1);	
	shmid=shmget(key,4,IPC_CREAT|IPC_EXCL|0666);
	if(shmid==-1) printf("get error:%m\n"),exit(-1);
	//2.挂载共享内存shmat
	p=shmat(shmid,0,0);
	if(p==(int*)-1) printf("at error:%m\n"),exit(-1);
	//3.访问共享内存
	while(1)
	{
		*p=i;
		sleep(1);
		i++;
	}
	
}

进程B

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/shm.h>
#include <sys/ipc.h>

key_t key;
int   shmid;
int   *p;

void deal(int s)
{
	if(s==2)
	{
		//4.卸载共享内存shmdt
		shmdt(p);
		exit(0);
	}
}

main()
{
	signal(SIGINT,deal);	
	//1.创建共享内存shmget
	key=ftok(".",255);
	if(key==-1) printf("ftok error:%m\n"),exit(-1);
	shmid=shmget(key,4,0);
	if(shmid==-1) printf("get error:%m\n"),exit(-1);
	//2.挂载共享内存shmat
	p=shmat(shmid,0,0);
	if(p==(int*)-1) printf("at error:%m\n"),exit(-1);
	//3.访问共享内存
	while(1)
	{		
		sleep(1);
		printf("%d\n",*p);
	}
}


linux进程通信之共享内存,布布扣,bubuko.com

linux进程通信之共享内存

原文:http://blog.csdn.net/aspnet_lyc/article/details/20915639

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!