Linux環境編程之共享內存區(一):共享內存區簡單介紹
共享內存區是可用IPC形式中最快的。一旦內存區映射到共享它的進程的地址空間,進程間數據的傳遞就不再涉及內核。然而往該共享內存區存放信息或從中取走信息的進程間通常須要某種形式的同步。不再涉及內核是指:進程不再通過運行不論什麽進入內核的系統調用來彼此傳遞數據。內核必須建立同意各個進程共享該內存區的內存映射關系。然後一直管理內存區。
默認情況下通過fork派生的子進程並不與其父進程共享內存區。
mmap函數把一個文件或一個Posix共享內存區對象映射到調用進程的地址空間。使用該函數的目的有:
1、使用普通文件以提供內存映射I/O。
2、使用特殊文件以提供匿名內存映射。
3、使用shm_open以提供無親緣關系進程間的Posix共享內存區。
#include <sys/mman.h> void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
addr指定描寫敘述符fd應被映射到的進程內空間的起始地址。
若為空指針,則由內核自己去選擇起始地址。不管哪種情況。該函數的返回值都是描寫敘述符fd所映射到內存區的起始地址。
len是映射到調用進程地址空間中的字節數,它從被映射文件開頭起第offset個字節處開始算。
offset通常設置為0。
prot參數指定內存區映射區的保護。
有下面四種:PROT_READ(數據可讀)、PROT_WRITE(數據可寫)、PROT_EXEC(數據可運行)、PROT_NONE(數據不可訪問)。
flags有下面三種:MAP_SHARED(變動是共享的)、MAP_PRIVATE(變動是私有的)、MAP_FIXED(準確地解釋addr參數)。
父子進程之間共享內存區的方法之中的一個是,父進程在調用fork前先指定MAP_SHARED調用mmap。
mmap成功返回後,fd參數能夠關閉。該操作對由mmap建立的映射關系沒有影響。
為某個進程的地址空間刪除一個映射關系,我們調用munmap。
(int munmap(void *addr, size_t len))
調用msync來運行同步。
(int msync(void *addr, size_t len, int flags))
註意:不是全部文件都能進程內存映射,比如:試圖把一個訪問終端或套接字的描寫敘述符映射到內存將導致mmap返回一個錯誤。這些類型的描寫敘述符必須使用read和write來訪問。
mmap的還有一個用途是在無親緣關系的進程間提供共享的內存區。
程序實例:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <semaphore.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/mman.h> #define SEM_NAME "mysem" #define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) int main(int argc, char **argv) { int fd, i, nloop, zero = 0; int *ptr; sem_t *mutex; if(argc != 3){ printf("usage:incrl <pathname> <#nloops>\n"); return -1; } nloop = atoi(argv[2]); /*open file , initialize to 0, map into memory*/ fd = open(argv[1], O_RDWR | O_CREAT, FILE_MODE); write(fd, &zero, sizeof(int)); ptr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); close(fd); /*create, initialize, and unlink semaphore*/ mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, FILE_MODE, 1); if(mutex < 0){ printf("sem_open error.\n"); return -1; } sem_unlink(SEM_NAME); setbuf(stdout, NULL); /*stdout is unbuffered*/ if(fork() == 0){ for(i = 0; i < nloop; i++){ sem_wait(mutex); printf("child:%d\n", (*ptr)++); sem_post(mutex); } exit(0); } /*parent*/ for(i = 0; i < nloop; i++){ sem_wait(mutex); printf("parent:%d\n", (*ptr)++); sem_post(mutex); } exit(0); }註意:內存映射一個普通文件時,內存中映射區的大小通常等於該文件的大小。然而文件大小和內存映射區大小能夠不同。
Linux環境編程之共享內存區(一):共享內存區簡單介紹