进程间通信之共享内存
共享内存允许两个或多个进程共享一个给定的存储区。因为数据不需要在两个进程之间进行复制,所以这是一种最快的进程间通信方式。使用共享存储区的唯一窍门是多个进程之间对一个给定的存储区的同步访问。通常信号量被用来实现对共享存储访问的同步。
在linux系统中系统共享存储段的做大字节数为33554432,最小字节数为1;系统中共享存储段的最大段数4096,每个进程共享存储段的最大段数为4096.
获得共享内存标识符:
#include <sys/shm.h> int shmget(key_t key, size_t size, int flag); 返回值:成功返回共享内存ID,失败返回-1
参数size是共享内存的段的大小,如果正在创建一个新段,则必须指定size的大小,如果正在引用一个现存的段,则将size设置为0.
参数flag是表示对该段的操作,创建段的时候该标志应该为IPC_CREAT|0666,IPC_CREAT为创建共享内存,0666为可读可写权限。
参数key,键。这个概念比较模糊。通过函数ftok函数获得一个key。
#include <sys/ipc.h> key_t ftok(const char *path, int id); 返回值:成功返回键值,出错返回-1
path参数必须是一个存在的文件。
共享内存创建完成后,就可以使用shmat函数将其连接到它的地址空间中。
#include <sys/shm.h> void *shmat(int shmid, const void *addr, int flag); 返回值:成功返回指向共享内存的指针,出错返回-1
共享存储段连接到调用进程的那个地址上与addr参数以及在flag中是否指定SHM_RND位有关。
1、如果addr为0,则此段连接到由内核选择的第一个可用地址上,这是推荐的使用方式
2、如果addr非0,并且没有指定SHM_RND,则此段连接到addr所指的地址上。
除非指定在一种硬件上使用运行应用程序,否则是不应该指定共享内存所连接到的地址,所以一般addr指定位0,以便由内核选择地址。
对共享内存操作结束后,调用函数shmdt脱离该共享内存。注意,这并不是从系统中删除其标识符以及其数据结构,该标识符依然存在,直到某个进程调用shmctl特地删除,后面介绍shmctl函数。
#include <sys.shm.h> int shmdt(void *addr) 返回值:成功返回0,出错返回-1.
shmctl函数对共享内存执行多种操作。
#include <sys/shm.h> int shmctl(int shmid, int cmd, struct shmid_ds, *buf); 返回值:成功返回0,失败返回-1.
cmd参数指定下列5个命令,使其在shmid指定的共享内存上执行。
1、IPC_STAT 去此段的shmid_ds结构,并将它存放在由buf指向的结构中。
2、IPC_RMID从系统中删除共享内存段。我们用的最多的。
下面是我写的一个关于共享内存使用的程序;
#include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #include <sys/types.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> #include <stdio.h> #include <string.h> int sharememorycom; //调试打印宏定义 #define DBG(level,fmt,para...) \ { \ if(level) \ printf(fmt "\tFrom FileName:%s Function:%s Line:%d\n" , ##para, __FILE__, __FUNCTION__, __LINE__); \ } #define DBG_INFOR 0x01 //正常打印信息 #define DBG_WARNING 0x02 //处理警告异常 #define DBG_ERROR 0x04 //处理错误 #define SUCCESS 1 #define FAIL -1 typedef struct { int lx; int zt; } sharem; key_t shmkey; int createShm() { int shm_id = 0; static char *shmname = "aaa"; shmkey = ftok(shmname,0); if(shmkey==FAIL) { DBG(DBG_ERROR, "get shm key failure!\n"); return FAIL; } shm_id=shmget(shmkey,4096,IPC_CREAT|0666); if(shm_id==FAIL) { DBG(DBG_ERROR, "creat shm is fail\n"); perror("error"); return FAIL; } return SUCCESS; } int setshareshm(int lx,int zt) { int shm_id; sharem *p_map; shm_id=shmget(shmkey,4096,0666); if(shm_id==FAIL) { DBG(DBG_ERROR, "creat shm is fail\n"); perror("error"); return FAIL; } p_map=(sharem*)shmat(shm_id,NULL,0); (*p_map).lx=lx; (*p_map).zt=zt; if(shmdt(p_map)==FAIL) return FAIL; return 0x00; } int getshareshm() { int shm_id; int lx = 0; int zt = 0; sharem *p_map; shm_id=shmget(shmkey,4096,0666); if(shm_id==FAIL) { DBG(DBG_ERROR, "creat shm is fail\n"); perror("error"); return FAIL; } p_map = (sharem*)shmat(shm_id,NULL,0); lx = (*p_map).lx; zt = (*p_map).zt; printf("lx = %d, zt = %d\n", lx, zt); if(shmdt(p_map)==FAIL) return FAIL; return zt; } void sharememory() { static int count = 0; setshareshm(count, 0); count++; getshareshm(); } int main(void) { createShm(); while (1) { sharememory(); usleep(10*1000); } return 0; }