在 SunOS 5.10 操作系统中,实现共享内存应用程序的最有效方法是依赖 mmap(2) 以及系统的本机虚拟内存功能。有关更多信息,请参见第 1 章,内存和 CPU 管理。
SunOS 5.10 平台还支持 System V 共享内存,这是一种效率较低的将物理内存段附加到多个进程的虚拟地址空间的方法。 允许针对多个进程使用写入权限时,可以使用外部协议或机制(如信号量)防止出现不一致和冲突。
进程使用 shmget(2) 创建共享内存段。 还可以使用此调用获取现有共享段的 ID。 创建进程将以字节为单位设置此段的权限和大小。
共享内存段的初始属主可以使用 shmctl(2) 将拥有权指定给其他用户, 也可以撤消此指定。 其他具有适当权限的进程可以使用 shmctl(2) 在共享内存段上执行各种控制功能。
创建共享段之后,便可以使用 shmat(2) 将此段附加到进程地址空间。 可以使用 shmdt(2) 拆离此共享段。 附加进程必须具有相应的 shmat(2) 权限。 附加此段之后,进程便可以对其执行读写操作,如附加操作中请求的权限所允许的那样。 共享段可以由同一进程进行多次附加。
共享内存段由具有指向物理内存区域的唯一 ID 的控制结构说明。 此段的标识符称为 shmid。 可在 sys/shm.h 中找到共享内存段控制结构的结构定义。
shmget(2) 用于获取对共享内存段的访问。 当此调用成功时,便会返回共享内存段 ID (shmid)。 以下代码说明了 shmget(2)。
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> ... key_t key; /* key to be passed to shmget() */ int shmflg; /* shmflg to be passed to shmget() */ int shmid; /* return value from shmget() */ size_t size; /* size to be passed to shmget() */ ... key = ... size = ... shmflg) = ... if ((shmid = shmget (key, size, shmflg)) == –1) { perror("shmget: shmget failed"); exit(1); } else { (void) fprintf(stderr, "shmget: shmget returned %d\n", shmid); exit(0); } ...
shmctl(2) 用于更改共享内存段的权限和其他特性。 cmd 参数为以下控制命令之一。
锁定内存中的指定共享内存段。 进程必须具有超级用户的有效 ID,才能执行此命令。
解除锁定共享内存段。 进程必须具有超级用户的有效 ID,才能执行此命令。
返回控制结构中包含的状态信息,并将其放入 buf 指向的缓冲区中。 进程必须具有段的读取权限,才能执行此命令。
设置有效的用户和组标识以及访问权限。 进程必须具有属主、创建者或超级用户的有效 ID,才能执行此命令。
删除共享内存段。 进程必须具有属主、创建者或超级用户的有效 ID,才能执行此命令。
|
以下代码说明了 shmctl(2)。
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> ... int cmd; /* command code for shmctl() */ int shmid; /* segment ID */ struct shmid_ds shmid_ds; /* shared memory data structure to hold results */ ... shmid = ... cmd = ... if ((rtrn = shmctl(shmid, cmd, shmid_ds)) == –1) { perror("shmctl: shmctl failed"); exit(1); ...
shmat() 和 shmdt() 用于附加和拆离共享内存段(请参见 shmop(2) 手册页)。shmat(2) 返回指向共享段头的指针。shmdt(2) 可拆离位于 shmaddr 所指示的地址中的共享内存段。 以下代码说明了对 shmat(2) 和 shmdt(2) 的调用。
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> static struct state { /* Internal record of attached segments. */ int shmid; /* shmid of attached segment */ char *shmaddr; /* attach point */ int shmflg; /* flags used on attach */ } ap[MAXnap]; /* State of current attached segments. */ int nap; /* Number of currently attached segments. */ ... char *addr; /* address work variable */ register int i; /* work area */ register struct state *p; /* ptr to current state entry */ ... p = &ap[nap++]; p–>shmid = ... p–>shmaddr = ... p–>shmflg = ... p–>shmaddr = shmat(p->shmid, p->shmaddr, p->shmflg); if(p–>shmaddr == (char *)-1) { perror("shmat failed"); nap–-; } else (void) fprintf(stderr, "shmop: shmat returned %p\n", p–>shmaddr); ... i = shmdt(addr); if(i == –1) { perror("shmdt failed"); } else { (void) fprintf(stderr, "shmop: shmdt returned %d\n", i); for (p = ap, i = nap; i–-; p++) { if (p–>shmaddr == addr) *p = ap[–-nap]; } } ...