您的位置:首页 > 运维架构 > Linux

Linux-IPC之共享内存

2016-01-26 23:59 477 查看
System V(标准)共享内存机制: shmget  shmat  shmdt  shmctl

原理及实现:system V IPC机制下的共享内存本质是一段特殊的内存区域,进程间需要共享的数据被放在该共享内存区域中,所有需要访问该共享区域的进程都要把该共享区域映射到本进程的地址空间(虚拟地址空间)中去。这样一个使用共享内存的进程可以将信息写入该空间,而另一个使用共享内存的进程又可以通过简单的内存读操作获取刚才写入的信息,使得两个不同进程之间进行了一次信息交换,从而实现进程间的通信。共享内存允许一个或多个进程通过同时出现在它们的虚拟地址空间的内存进行通信,而这块虚拟内存的页面被每个共享进程的页表条目所引用,同时并不需要在所有进程的虚拟内存都有相同的地址。进程对象对于共享内存的访问通过key(键)来控制,同时通过key进行访问权限的检查。

进程结束时,共享内存是系统资源,不会消失。

命令ipcs查看共享内存。

命令ipcrm -m shmid删除共享内存。

函数原型:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
key_t ftok(const char *pathname, int proj_id);
int shmget(key_t key, int size, int shmflg);
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);


1、ftok()函数

作用:用于创建一个关键字,可以用该关键字关联一个共享内存段。

参数pathname为一个全路径文件名,并且该文件必须可访问。

参数proj_id通常传入一非0字符

通过pathname和proj_id组合可以创建唯一的key(整型数)

如果调用成功,返回一关键字,否则返回-1

示例:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#define PROJ_ID 1

int main(int argc,char* argv[])
{
if(argc!=2)
{
printf("error args\n");
return -1;
}
key_t skey;
skey=ftok(argv[1],PROJ_ID);
if(-1==skey)
{
perror("ftok");
return -1;
}
printf("the key is %d\n",skey);
return 0;
}


运行结果:



2、shmget()函数

作用:用于创建或打开一共享内存段,该内存段由函数的第一个参数唯一创建。函数成功,则返回一个唯一的共享内存标识号(相当于进程号,唯一的标识着共享内存),失败返回-1。

参数key是一个与共享内存段相关联关键字,如果事先已经存在一个与指定关键字关联的共享内存段,则直接返回该内存段的标识,表示打开,如果不存在,则创建一个新的共享内存段。key的值既可以用ftok函数产生,也可以是IPC_RPIVATE(用于创建一个只属于创建进程的共享内存,主要用于父子通信),表示总是创建新的共享内存段;

参数size指定共享内存段的大小,以字节为单位;

参数shmflg是一掩码合成值,可以是访问权限值与(IPC_CREAT或IPC_EXCL)的合成。IPC_CREAT表示如果不存在该内存段,则创建它。IPC_EXCL表示如果该内存段存在,则函数返回失败结果(-1)。如果调用成功,返回内存段标识,否则返回-1

示例:
//普通情况下创建共享内存
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <sys/shm.h>
#define PROJ_ID 1

int main(int argc,char* argv[])
{
if(argc!=2)
{
printf("error args\n");
return -1;
}
key_t skey;
skey=ftok(argv[1],PROJ_ID);
if(-1==skey)
{
perror("ftok");
return -1;
}
printf("the key is %d\n",skey);
int shmid;
shmid=shmget(skey,1<<12,0600|IPC_CREAT);
if(-1==shmid)
{
perror("shmget");
return -1;
}
printf("the shmid is %d\n",shmid);
return 0;
}


运行结果:



//key的值为IPC_RPIVATE
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <sys/shm.h>
#define PROJ_ID 1

int main(int argc,char* argv[])
{
int shmid;
shmid=shmget(IPC_PRIVATE,1<<12,0600|IPC_CREAT);
if(-1==shmid)
{
perror("shmget");
return -1;
}
printf("the shmid is %d\n",shmid);
return 0;
}

运行结果:



(key的值为0)

//手动给key赋值
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <sys/shm.h>
#define PROJ_ID 1

int main(int argc,char* argv[])
{
int shmid;
shmid=shmget((key_t)1234,1<<12,0600|IPC_CREAT);
if(-1==shmid)
{
perror("shmget");
return -1;
}
printf("the shmid is %d\n",shmid);
return 0;
}

运行结果:



(4b2为1234的十六进制形式)

3、shmat()函数

作用:将共享内存段映射到进程空间的某一地址。

参数shmid是共享内存段的标识  通常应该是shmget的成功返回值

参数shmaddr指定的是共享内存连接到当前进程中的地址位置。通常是NULL,表示让系统来选择共享内存出现的地址。

参数shmflg是一组位标识,通常为0即可。

如果调用成功,返回映射后的进程空间的首地址,否则返回(char *)-1。

示例:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <sys/shm.h>
#define PROJ_ID 1

int main(int argc,char* argv[])
{
if(argc!=2)
{
printf("error args\n");
return -1;
}
key_t skey;
skey=ftok(argv[1],PROJ_ID);
if(-1==skey)
{
perror("ftok");
return -1;
}
printf("the key is %d\n",skey);
int shmid;
shmid=shmget(skey,1<<12,0600|IPC_CREAT);
if(-1==shmid)
{
perror("shmget");
return -1;
}
printf("the shmid is %d\n",shmid);
char* p;
p=shmat(shmid,NULL,0);
if((char*)-1==p)
{
perror("shmat");
return -1;
}
while(1);
return 0;
}


运行结果:



程序未结束时:



连接数是1

程序结束时:



连接数是0

//赋值输出
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <sys/shm.h>
#define PROJ_ID 1

int main(int argc,char* argv[])
{
if(argc!=2)
{
printf("error args\n");
return -1;
}
key_t skey;
skey=ftok(argv[1],PROJ_ID);
if(-1==skey)
{
perror("ftok");
return -1;
}
printf("the key is %d\n",skey);
int shmid;
shmid=shmget(skey,1<<12,0600|IPC_CREAT);
if(-1==shmid)
{
perror("shmget");
return -1;
}
printf("the shmid is %d\n",shmid);
char* p;
p=shmat(shmid,NULL,0);
if((char*)-1==p)
{
perror("shmat");
return -1;
}
*p='1';//赋值
return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <sys/shm.h>
#define PROJ_ID 1

int main(int argc,char* argv[])
{
if(argc!=2)
{
printf("error args\n");
return -1;
}
key_t skey;
skey=ftok(argv[1],PROJ_ID);
if(-1==skey)
{
perror("ftok");
return -1;
}
printf("the key is %d\n",skey);
int shmid;
shmid=shmget(skey,1<<12,0600|IPC_CREAT);
if(-1==shmid)
{
perror("shmget");
return -1;
}
printf("the shmid is %d\n",shmid);
char* p;
p=shmat(shmid,NULL,0);
if((char*)-1==p)
{
perror("shmat");
return -1;
}
printf("the *p is %c\n",*p);//输出
return 0;
}


运行结果:



(即使进程都崩溃掉,共享内存中还保留着当时操作时的现场)

4、shmdt()函数

作用:用于将共享内存段与进程空间分离。

参数shmaddr通常为shmat的成功返回值。

函数成功返回0,失败时返回-1.注意,将共享内存分离并没删除它,只是使得该共享内存对当前进程不在可用。

示例:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <sys/shm.h>
#define PROJ_ID 1

int main(int argc,char* argv[])
{
if(argc!=2)
{
printf("error args\n");
return -1;
}
key_t skey;
skey=ftok(argv[1],PROJ_ID);
if(-1==skey)
{
perror("ftok");
return -1;
}
printf("the key is %d\n",skey);
int shmid;
shmid=shmget(skey,1<<12,0600|IPC_CREAT);
if(-1==shmid)
{
perror("shmget");
return -1;
}
printf("the shmid is %d\n",shmid);
char* p;
p=shmat(shmid,NULL,0);
if((char*)-1==p)
{
perror("shmat");
return -1;
}
int ret;
ret=shmdt(p);
if(-1==ret)
{
perror("shmdt");
return -1;
}
while(1);
return 0;
}


进程:



解除链接,连接数为0

5、shmctl()函数

是共享内存的控制函数,可以用来删除共享内存段。

参数shmid是共享内存段标识 通常应该是shmget的成功返回值

参数cmd是对共享内存段的操作方式,可选为IPC_STAT,IPC_SET,IPC_RMID。通常为IPC_RMID,表示删除共享内存段。

参数buf是表示共享内存段的信息结构体数据,通常为NULL。

//shmid_ds结构体
struct shmid_ds {
struct ipc_perm shm_perm;    /* Ownership and permissions */
size_t          shm_segsz;   /* Size of segment (bytes) */
time_t          shm_atime;   /* Last attach time */
time_t          shm_dtime;   /* Last detach time */
time_t          shm_ctime;   /* Last change time */
pid_t           shm_cpid;    /* PID of creator */
pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
shmatt_t        shm_nattch;  /* No. of current attaches */
...
};
struct ipc_perm {
key_t          __key;    /* Key supplied to shmget(2) */
uid_t          uid;      /* Effective UID of owner */
gid_t          gid;      /* Effective GID of owner */
uid_t          cuid;     /* Effective UID of creator */
gid_t          cgid;     /* Effective GID of creator */
unsigned short mode;     /* Permissions + SHM_DEST and
SHM_LOCKED flags */
unsigned short __seq;    /* Sequence number */
};

ipc_perm的mode详解表
操作者

写(更改更新)
操作者

写(更改更新)
用户
0400
0200
其他
0004
0002

0040
0020
 

 

 

//IPC_RMID删除共享内存
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <sys/shm.h>
#define PROJ_ID 1

int main(int argc,char* argv[])
{
if(argc!=2)
{
printf("error args\n");
return -1;
}
key_t skey;
skey=ftok(argv[1],PROJ_ID);
if(-1==skey)
{
perror("ftok");
return -1;
}
printf("the key is %d\n",skey);
int shmid;
shmid=shmget(skey,1<<12,0600|IPC_CREAT);
if(-1==shmid)
{
perror("shmget");
return -1;
}
printf("the shmid is %d\n",shmid);
int ret;
if(-1==ret)
{
perror("shmctl_rmid");
return -1;
}
return 0;
}


//IPC_STAT获取共享内存信息
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <sys/shm.h>
#define PROJ_ID 1

int main(int argc,char* argv[])
{
if(argc!=2)
{
printf("error args\n");
return -1;
}
key_t skey;
skey=ftok(argv[1],PROJ_ID);
if(-1==skey)
{
perror("ftok");
return -1;
}
printf("the key is %d\n",skey);
int shmid;
shmid=shmget(skey,1<<12,0600|IPC_CREAT);
if(-1==shmid)
{
perror("shmget");
return -1;
}
printf("the shmid is %d\n",shmid);
int ret;
struct shmid_ds buf;
ret=shmctl(shmid,IPC_STAT,&buf);
if(-1==ret)
{
perror("shmctl_stat");
return -1;
}
printf("euid=%d,cuid=%d,mode=%u\n",buf.shm_perm.uid,buf.shm_perm.cuid,buf.shm_perm.mode);
printf("size=%d,cpid=%d,nattch=%lu\n",buf.shm_segsz,buf.shm_cpid,buf.shm_nattch);
return 0;
}

共享内存:



运行结果:



//IPC_SET设置共享内存属性
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <sys/shm.h>
#define PROJ_ID 1

int main(int argc,char* argv[])
{
if(argc!=2)
{
printf("error args\n");
return -1;
}
key_t skey;
skey=ftok(argv[1],PROJ_ID);
if(-1==skey)
{
perror("ftok");
return -1;
}
printf("the key is %d\n",skey);
int shmid;
shmid=shmget(skey,1<<12,0600|IPC_CREAT);
if(-1==shmid)
{
perror("shmget");
return -1;
}
printf("the shmid is %d\n",shmid);
int ret;
struct shmid_ds buf;
ret=shmctl(shmid,IPC_STAT,&buf);
if(-1==ret)
{
perror("shmctl_stat");
return -1;
}
printf("euid=%d,cuid=%d,mode=%u\n",buf.shm_perm.uid,buf.shm_perm.cuid,buf.shm_perm.mode);
printf("size=%d,cpid=%d,nattch=%lu\n",buf.shm_segsz,buf.shm_cpid,buf.shm_nattch);
buf.shm_perm.mode=0660;
ret=shmctl(shmid,IPC_SET,&buf);
if(-1==ret)
{
perror("shmctl_set");
return -1;
}
return 0;
}

共享内存(与上图对比):

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