Posted on 2012-01-02 23:36
S.l.e!ep.¢% 阅读(2269)
评论(0) 编辑 收藏 引用 所属分类:
Unix
使用共享内存的目的:
共享内存共享内存是进程间通信中最简单的方式之一。
共享内存允许两个或更多进程访问同一块内存,就如同 malloc() 函数向不同进程返回了指向同一个物理内存区域的指针。
当一个进程改变了这块地址中的内容的时候,其它进程都会察觉到这个更改。
使用共享内存的流程:
1.进程必须首先分配它。
2.随后需要访问这个共享内存块的每一个进程都必须将这个共享内存绑定到自己的地址空间中。
3.当完成通信之后,所有进程都将脱离共享内存,并且由一个进程释放该共享内存块。
分配:
int segment_id = shmget (shm_key, int size , shmflag );
1.进程通过调用shmget(Shared Memory GET,获取共享内存)来分配一个共享内存块。 该函数的第一个参数是一个用来标识共享内存块的键值。
彼此无关的进程可以通过指定同一个键以获取对同一个共享内存块的访问。
不幸的是,其它程序也可能挑选了同样的特定值作为自己分配共享内存的键值,从而产生冲突。
用特殊常量IPC_PRIVATE作为键值可以保证系统建立一个全新的共享内存块。
2.该函数的第二个参数指定了所申请的内存块的大小。
因为这些内存块是以页面为单位进行分配的,实际分配的内存块大小将被扩大到页面大小的整数倍。
3.第三个参数是一组标志,通过特定常量的按位或操作来shmget。这些特定常量包括:
IPC_CREAT:
这个标志表示应创建一个新的共享内存块。通过指定这个标志,我们可以创建一个具有指定键值的新共享内存块。
IPC_EXCL:
这个标志只能与 IPC_CREAT 同时使用。当指定这个标志的时候,如果已有一个具有这个键值的共享内存块存在,则shmget会调用失败。
也就是说,这个标志将使线程获得一个“独有”的共享内存块。如果没有指定这个标志而系统中存在一个具有相通键值的共享内存块,
shmget会返回这个已经建立的共享内存块,而不是重新创建一个。
模式标志:
这个值由9个位组成,分别表示属主、属组和其它用户对该内存块的访问权限。其中表示执行权限的位将被忽略。
指明访问权限的一个简单办法是利用<sys/stat.h>中指定,并且在手册页第二节stat条目中说明了的常量指定。
例如,
S_IRUSR和S_IWUSR分别指定了该内存块属主的读写权限,
S_IROTH和S_IWOTH则指定了其它用户的读写权限。
绑定和脱离:
pst= shmat(iShm_id, NULL, 0)
一个进程获取对一块共享内存的访问,这个进程必须先调用 shmat(SHared Memory Attach,绑定到共享内存)。
将 shmget 返回的共享内存标识符 SHMID 传递给这个函数作为第一个参数。
第二个参数是一个指针,指向您希望用于映射该共享内存块的进程内存地址;如果您指定NULL则Linux会自动选择一个合适的地址用于映射。
第三个参数是一个标志位,包含了以下选项:
SHM_RND
表示第二个参数指定的地址应被向下靠拢到内存页面大小的整数倍。
如果您不指定这个标志,您将不得不在调用shmat的时候手工将共享内存块的大小按页面大小对齐。
SHM_RDONLY
表示这个内存块将仅允许读取操作而禁止写入。 如果这个函数调用成功则会返回绑定的共享内存块对应的地址。
通过 fork 函数创建的子进程同时继承这些共享内存块;
如果需要,它们可以主动脱离这些共享内存块。
当一个进程不再使用一个共享内存块的时候应通过调用 shmdt(Shared Memory Detach,脱离共享内存块)
函数与该共享内存块脱离。将由 shmat 函数返回的地址传递给这个函数。
如果当释放这个内存块的进程是最后一个使用该内存块的进程,则这个内存块将被删除。
对 exit 或任何exec族函数的调用都会自动使进程脱离共享内存块。
控制和释放共享内存块:
shmctl(iShm_id,IPC_RMID,0)<0
调用 shmctl("Shared Memory Control",控制共享内存)函数会返回一个共享内存块的相关信息。同时 shmctl 允许程序修改这些信息。
该函数的第一个参数是一个共享内存块标识。要获取一个共享内存块的相关信息,则为该函数传递 IPC_STAT 作为第二个参数,同时传递一个指向一个 struct shmid_ds 对象的指针作为第三个参数。
要删除一个共享内存块,则应将 IPC_RMID 作为第二个参数,而将 NULL 作为第三个参数。当最后一个绑定该共享内存块的进程与其脱离时,该共享内存块将被删除。
应当在结束使用每个共享内存块的时候都使用 shmctl 进行释放,以防止超过系统所允许的共享内存块的总数限制。调用 exit 和 exec 会使进程脱离共享内存块,
但不会删除这个内存块。 要查看其它有关共享内存块的操作的描述,请参考shmctl函数的手册页。
共享内存的总体大小是有限制的,这个大小通过SHMMAX参数来定义(以字节为单位),
您可以通过执行以下命令来确定 SHMMAX 的值:
cat /proc/sys/kernel/shmmax
修改共享内存:
设置 SHMMAX
# >echo "2147483648" > /proc/sys/kernel/shmmax
您还可以使用 sysctl 命令来更改 SHMMAX 的值:
# sysctl -w kernel.shmmax=2147483648
最后,通过将该内核参数插入到 /etc/sysctl.conf 启动文件中,您可以使这种更改永久有效:
# echo "kernel.shmmax=2147483648" >> /etc/sysctl.conf
====================================================================
/*********************************************************
* filename: ipc.c
* author: wjy
* date: 20110509
*********************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
int main(int argc,char *argv[])
{
key_t shmid;
char *p_addr,*c_addr;
pid_t pid;
if(argc != 2)
{
printf("Usage:program something",argv[0]);
exit(0);
}
if((shmid = shmget(IPC_PRIVATE,1024,S_IRUSR|S_IWUSR)) == -1)
{
printf("create share memory error/n");
exit(1);
}
pid = fork();
if(pid > 0 )
{
p_addr = shmat(shmid,0,0);
memset(p_addr,'/0',1024);
strncpy(p_addr,argv[1],1024);
wait(NULL);
}
else if (pid == 0)
{
sleep(1);
c_addr = shmat(shmid,0,0);
printf("Client get %s/n",c_addr);
exit(0);
}
if(shmctl(shmid,IPC_RMID,0)<0)
{
printf("共享内存释放出错!!/n");
return(-1);
}
else
printf("释放共享内存成功!/n");
}