共享内存(shared memory):是linux下的多进程之间的通信方法,这种方法通常用于一个程序的多进程间通信,实际上多个程序间也可以通过共享内存来传递信息。共享内存指在多处理器的计算机系统中,可以被不同中央处理器(CPU)访问的大容量内存。由于多个CPU需要快速访问存储器,这样就要对存储器进行缓存(Cache)。共享内存是存在于内核级别的一种资源,在shell中可以使用ipcs命令来查看当前系统IPC中的状态,在文件系统/proc目录下有对其描述的相应文件。共享内存相比其他几种方式有着更方便的数据控制能力,数据在读写过程中会更透明。
共享内存使用的函数
#include
#include
int shmget(key_t key, size_t size, int shmflg);
void *shmat(int shm_id, const void *shm_addr, int shmflg);
int shmdt(const void *shm_addr);
int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
(1)shmget函数
该函数用来创建共享内存:
int shmget(key_t key, size_t size, int shmflg);
参数:
a.key : 和信号量一样,程序需要提供一个参数key,
它有效地为共享内存段命名。
通常使用ftok()函数获取key值。
有一个特殊的键值IPC_PRIVATE, 它用于创建一个只属于创建进程的共享内存,通常不会用到。
b.size: 以字节为单位指定需要共享的内存容量。内核是以页为单位分配内存,当size参数的值不是系统内存页长的整数倍时,系统会分配给进程最小的可以满足size长的页数,但是最后一页的剩余部分内存是不可用的。
c.shmflag: 包含9个比特的权限标志,
它们的作用与创建文件时使用的mode标志是一样。
由IPC_CREAT定义的一个特殊比特必须和权限标志IPC_EXCL按位或
才能创建一个新的共享内存段。
NOTE:
权限标志对共享内存非常有用,因为它允许一个进程创建的共享内存可以被共享内存的创建者所拥有的进程写入,同时其它用户创建的进程只能读取共享内存。
我们可以利用这个功能来提供一种有效的对数据进行只读访问的方法,通过将数据放共享内存并设置它的权限,就可以避免数据被其他用户修改。
返回值:
创建成功,则返回一个非负整数,即共享内存标识;如果失败,则返回-1.
(2)shmat函数(挂接)
第一次创建共享内存段时,它不能被任何进程访问。要想启动对该内存的访问,必须将其连接到一个进程的地址空间。
这个工作由shmat函数完成:
函数原型:void *shmat(int shm_id, const void *shm_addr, int shmflg);
参数:
shm_id : 由shmget返回的共享内存标识。
shm_addr: 指定共享内存连接到当前进程中的地址位置。它通常是一个空指针, 表示让系统来选择共享内存出现的地址。
shmflg : 是一组标志。它的两个可能取值是SHM_RND, 和shm_addr联合使用, 用来控制共享内存连接的地址。SHM_RDONLY, 它使连接的内存只读
返回值:
如果调用成功, 返回一个指向共享内存第一个字节的指针;
如果失败,返回-1.
共享内存的读写权限由它的属主(共享内存的创建者),
它的访问权限由当前进程的属主决定。
共享内存的访问权限类似于文件的访问权限。
(3)shmdt(去关联)
将共享内存从当前进程中分离。
int shmdt(const void *shm_addr);
shm_addr: shmat返回的地址指针。
成功时,返回0,
失败时,返回-1.
NOTE:
共享内存分离并未删除它,
只是使得该共享内存对当前进程不再可用。
(4)shmctl函数
共享内存的控制函数
int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
shmid_ds结构至少包含以下成员:
struct shmid_ds {
uid_t shm_perm.uid;
uid_t shm_perm.gid;
mode_t shm_perm.mode;
}
参数:
shm_id : 是shmget返回的共享内存标识符。
command: 是要采取的动作,
它可以取3个值:
IPC_STAT 把shmid_ds结构中的数据设置为共享内存的当前关联值
IPC_SET 如果进程有足够的权限,
就把共享内存的当前关联值设置为shmid_ds结构中给出的值
IPC_RMID 删除共享内存段
buf : 是一个指针,
包含共享内存模式和访问权限的结构。
返回值:
成功时,返回0,
失败时,返回-1.
下面实例演示了操作共享内存段的流程。
comm.h代码:
源代码:
#ifndef __COMM_H__
#define __COMM_H__
#include
#include
#include
#define PATHNAME "."
#define PROJ_ID 0x6666
int createShm(int size);
int getShm();
int destoryShm(int shmid);
#endif
源代码:
int CommShm(int size,int flags)
{
int key=ftok(PATHNAME,PROJ_ID);
if(key<0)
{
perror("ftok");
return -1;
}
int shmid=shmget(key,size,flags);
if(shmid<0)
{
perror("shmid");
return -2;
}
return shmid;
}
int CreateShm(int size)
{
return CommShm(size, IPC_CREAT|IPC_EXCL|0666);
}
int GetShm()
{
return CommShm(0, IPC_CREAT);
}
int DestoryShm(int shmid)
{
if(shmctl(shmid,IPC_RMID,NULL)<0)
{
perror("shmctl");
return -1;
}
return 0;
}
源代码:
int main()
{
int count = 0;
int shmid = CreateShm(4096);
sleep(5);
char *buf = shmat(shmid, NULL, 0);
while(count<4096)
{
buf[count] = 'A'+count%26;
sleep(2);
count++;
buf[count] = '\0';
}
shmdt(buf);
sleep(5);
DestoryShm(shmid);
return 0;
}
源代码:
#include "comm.h"
int main()
{
int shmid = GetShm();
sleep(5);
char* buf = shmat(shmid, NULL, 0);
while(1)
{
printf("%s\n", buf);
sleep(2);
}
shmdt(buf);
return 0;
}