共享内存区是可用IPC形式中最快的。当共享内存区映射到共享它的进程的地址空间,进程间数据的传递就不再涉及内核;往该共享内存区存放信息或从中取走信息的进程间通常需要某种形式的同步。
#include <sys/mman.h> void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset); // return ptr/MAP_FAILEDaddr可以指定描述符fd应被映射到的进程内空间的起始地址。它通常被指定为一个空指针,内核可以自己去选择地址;无论如何函数的返回值都是fd所映射到内存区的起始地址。
len是映射到调用进程地址空间中的字节数,它从被映射文件开头起第offset个字节处开始算。
内存映射区的保护由prot参数指定,常见的读写为PROT_READ | PROT_WRITE。
flags, MAP_SHARED或MAP_PRIVATE必须制定一个,如果指定MAP_PRIVATE,那么调用进程对被映射数据的修改只对该进程可见,而不改变其底层支撑对象。如果指定MAP_SHARED,那么调用进程对被映射数据所作的修改对于共享该对象的所有进程都可见,而且确实改变了其底层支撑对象。
父子进程之间共享内存区的方法之一是,父进程在调用fork前先指定MAP_SHARED调用mmap,Posix保证父进程中的内存映射关系存留到子进程中,修改双方均能看到。mmap成功返回之后,fd参数可以关闭。
int munmap(void *addr, size_t len); // return 0/-1删除映射后,再次访问这些地址将导致向调用进程产生一个SIGSEGV;如果被映射区是使用MAP_PRIVATE标志映射,那么调用进程对它所作的变动都会被丢弃掉
内核的虚拟内存算法保持内存映射文件与内存映射区的同步,前提是它是一个MAP_SHARED内存区,我们也可以通过调用msync来执行这种同步。
// 计数器和信号量都在共享内存区中保存,父子进程持续给计数器加1 #include "unpipc.h" struct shared { sem_t mutex; /* the mutex: a Posix memory-based semaphore */ int count; /* and the counter */ } shared; int main(int argc, char **argv) { int fd, i, nloop; struct shared *ptr; if (argc != 3) err_quit("usage: incr3 <pathname> <#loops>"); nloop = atoi(argv[2]); /* 4open file, initialize to 0, map into memory */ fd = Open(argv[1], O_RDWR | O_CREAT, FILE_MODE); Write(fd, &shared, sizeof(struct shared)); ptr = Mmap(NULL, sizeof(struct shared), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); Close(fd); /* 4initialize semaphore that is shared between processes */ Sem_init(&ptr->mutex, 1, 1); setbuf(stdout, NULL); /* stdout is unbuffered */ if (Fork() == 0) { /* child */ for (i = 0; i < nloop; i++) { Sem_wait(&ptr->mutex); printf("child: %d\n", ptr->count++); Sem_post(&ptr->mutex); } exit(0); } /* 4parent */ for (i = 0; i < nloop; i++) { Sem_wait(&ptr->mutex); printf("parent: %d\n", ptr->count++); Sem_post(&ptr->mutex); } exit(0); }
// 匿名内存映射 int main(int argc, char **argv) { int i, nloop; int *ptr; sem_t *mutex; if (argc != 2) err_quit("usage: incr_map_anon <#loops>"); nloop = atoi(argv[1]); /* 4map into memory */ ptr = Mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); /* end diff */ /* 4create, initialize, and unlink semaphore */ mutex = Sem_open(SEM_NAME, O_CREAT | O_EXCL, FILE_MODE, 1); .........../dev/zero内存映射,从该设备读时,返回字节全为0,写的任何字节则被丢弃
/* /dev/zero */ int main(int argc, char **argv) { int fd, i, nloop; int *ptr; sem_t *mutex; if (argc != 2) err_quit("usage: incr_dev_zero <#loops>"); nloop = atoi(argv[1]); /* 4open /dev/zero, map into memory */ fd = Open("/dev/zero", O_RDWR); ptr = Mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); Close(fd); ..................