共享内存------总结
共享内存是允许两个或多个进程共享一给定的区域。因为数据不需要在客户机和服务器之间复制,所以这是最快的一种IPC.使用共享内存的唯一诀窍就是多个进程对一定区域的同步存取。若服务器将数据放到共享内存区,则在服务器做完这一操作之前,客户机不应该去取这些数据。通常信号量被用来实现对共享内存存取的同步。
系统通过调用shmget()来分配一个共享内存块,该函数的第一个参数是一个用来标识共享内存块的键值。彼此无关的进程可以通过指定同一键来获取对共享内存块
的访问。不幸的是其他程序也可能挑选了同样的特定值作为自己分配共享内存的键值。不幸的是其他程序也可能挑选了同样的键值作为自己分配共享内存的键值,从
而产生冲突 。用信号量IPC_PRIVATE作为键值可以保证系统建立一个全新的共享内存块。 IPC_EXCL:这个标志只能与 IPC_CREAT 同时使用。当指定这个标志的时候,如果已有一个具有这个键值的共享内存块存在,则shmget会调用失败。也就是说,这个标志将使线程获得一个“独有”的共享内存块。如果没有指定这个标志而系统中存在一个具有相通键值的共享内存块,shmget会返回这个已经建立的共享内存块,而不是重新创建一个。 模式标志:这个值由9个位组成,分别表示属主、属组和其它用户对该内存块的访问权限。其中表示执行权限的位将被忽略。指明访问权限的一个简单办法是利用<sys/stat.h>中指定,并且在手册页第二节stat条目中说明了的常量指定。例如,S_IRUSR和S_IWUSR分别指定了该内存块属主的读写权限,而 S_IROTH和S_IWOTH则指定了其它用户的读写权限。 下面例子中shmget函数创建了一个新的共享内存块(当shm_key已被占用时则获取对一个已经存在共享内存块的访问),且只有属主对该内存块具有读写权限,其它用户不可读写。 int segment_id = shmget (shm_key, getpagesize (), IPC_CREAT | S_IRUSR| S_IWUSR ); 如果调用成功,shmget将返回一个共享内存标识符。如果该共享内存块已经存在,系统会检查访问权限,同时会检查该内存块是否被标记为等待摧毁状态。
绑定和脱离
调用 shmctl("Shared Memory Control",控制共享内存)函数会返回一个共享内存块的相关信息。同时 shmctl 允许程序修改这些信息。该函数的第一个参数是一个共享内存块标识。 要获取一个共享内存块的相关信息,则为该函数传递 IPC_STAT 作为第二个参数,同时传递一个指向一个 struct shmid_ds 对象的指针作为第三个参数。 要删除一个共享内存块,则应将 IPC_RMID 作为第二个参数,而将 NULL 作为第三个参数。当最后一个绑定该共享内存块的进程与其脱离时,该共享内存块将被删除。 您应当在结束使用每个共享内存块的时候都使用 shmctl 进行释放,以防止超过系统所允许的共享内存块的总数。调用 exit 和 exec 会使进程脱离共享内存块,但不会删除这个内存块。 要查看其它有关共享内存块的操作的描述,请参考shmctl函数的手册页。
代码 5.1 中的程序展示了共享内存块的使用。
代码 5.1 (shm.c) 尝试共享内存
#include <stdio.h>
#include <sys/shm.h>
#include <sys/stat.h>
int main() {
int segment_id;
char* shared_memory;
struct shmid_ds shmbuffer;
int segment_size;
const int shared_segment_size = 0x00; /* 分配一个共享内存块 */
segment_id = shmget(IPC_PRIVATE, shared_segment_size, IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR ); /* 绑定到共享内存块 */
shared_memory = (char*)shmat(segment_id, 0, 0);
printf("shared memory attached at address %p\n", shared_memory); /* 确定共享内存的大小 */
shmctl(segment_id, IPC_STAT, &shmbuffer); segment_size = shmbuffer.shm_segsz; printf("segment size: %d\n", segment_size); sprintf(shared_memory, "Hello, world."); /* 在共享内存中写入一个字符串 */
shmdt(shared_memory); /* 脱离该共享内存块 */
shared_memory = (char*)shmat(segment_id, (void*) 0x500000, 0);/* 重新绑定该内存块 */
printf("shared memory reattached at address %p\n", shared_memory);
printf("%s\n", shared_memory); /* 输出共享内存中的字符串 */
shmdt(shared_memory); /* 脱离该共享内存块 */
shmctl(segment_id, IPC_RMID, 0);/* 释放这个共享内存块 */
return 0; }
使用ipcs 命令可用于查看系统中包括共享内存在内的进程间通信机制的信息。指定-m参数以获取有关共享内存的信息。例如,以下的示例表示有一个编号为16279的共享内存块正在使用中: % ipcs -m ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 16279 user 0 25600 0 如果这个共享内存块在程序结束后没有被删除而是被错误地保留下来,您可以用ipcrm命令删除它。 % ipcrm shm 16279
控制和释放共享内存块