Linux 支持兩種方式的共享內存:System V 和 POSIX 共享內存。函數
System V 共享內存和共享文件映射的不足:ui
基於以上不足,POSIX.1b 定義了一組新的共享內存 API: POSIX 共享內存。code
POSIX 共享內存可以讓無關進程共享一個映射區域而無需建立一個相應的映射文件。Linux 從內核 2.4 起開始支持 POSIX 共享內存。對象
不少類 UNIX 實現採用了文件系統來標識共享內存對象。一些 UNIX 實現將共享內存對象名建立爲標準文件系統上一個特殊位置處的文件。Linux 使用掛載於 /dev/shm 目錄下的專用 tmpfs 文件系統. 這個文件系統具備內核持久性--它所包含的共享內存對象會一直持久,即便當前不存在任何進程打開它,但這些對象會在系統關閉以後丟失.進程
系統上 POSIX 共享內存區域佔據的內存總量受限於底層的 tmpfs 文件系統的大小。這個文件系統一般會在啓動時使用默認大小(如 256 MB)進行掛載。若是有必要的話,超級用戶可以經過使用命令 mount -o remount,size=
從新掛載這個文件系統來修改它的大小。 ip
使用 POSIX 共享內存對象的流程:內存
shm_open() 函數建立和打開一個新的共享內存對象或打開一個既有對象。傳入 shm_open() 的參數與傳入 open()的參數相似。rem
#include <sys/mman.h> #include <sys/stat.h> /* For mode constants */ #include <fcntl.h> /* For O_* constants */ int shm_open(const chart *name, int oflag, mode_t mode); Returns file descriptor on success, or -1 on error. Link with -lrt.
name 參數標識出了待建立或待打開的共享內存對象。oflag 參數是一個改變調用行爲的位掩碼。字符串
oflag 參數的位值:string
在一個新共享內存對象被建立時,其全部權和組全部權將根據調用 shm_open() 的進程的有效用戶和組 ID 來設定,對象權限將會根據 mode 參數中設置的掩碼值來設定。mode 參數能取的位值與文件上的權限位值是同樣的。與 open() 系統調用同樣,mode 中的權限掩碼將會根據進程的 umask 來取值。與 open() 不一樣的是,在調用 shm_open() 時老是須要 mode 參數,在不建立新對象時須要將這個參數值指定爲 0.
shm_open() 返回的文件描述符會設置 close-on-exec 標記,所以當程序執行了一個 exec() 時文件描述符會被自動關閉。
一個新共享內存對象被建立時其初始長度被會設置爲 0。這意味着在建立完一個新共享內存對象以後一般在調用 mmap() 以前須要調用 ftruncate() 來設置對象的大小。在調用完 mmap() 以後可能還須要使用 ftuncate() 來根據需求擴大或收縮共享內存對象。
在擴展一個共享內存對象時,新增長的字節會自動被初始化爲 0。
在任什麼時候候均可以在 shm_open() 返回的文件描述符上使用 fstat() 以獲取一個 stat 結構,該結構的字段會包含與這個共享內存對象相關的信息,包括其大小(st_size)、權限(st_mode)、全部者(st_uid)以及組(st_gid)。
使用 fchmod() 和 fchown() 可以分別修改共享內存對象的權限和全部權。
該程序建立了一個大小經過命令參數指定的共享內存對象並將該對象映射進進程的虛擬地址空間。
#include<stdio.h> #include<string.h> #include<fcntl.h> #include<sys/mman.h> #include<sys/stat.h> #include <unistd.h> #include <stdlib.h> int main(int argc, char *argv[]) { int flags, opt, fd; mode_t perms; size_t size; void *addr; /* Create shared memory object and set its size */ fd = shm_open(argv[1], O_RDWR|O_CREAT, 0777); if (fd == -1) { printf("shm_open failed"); exit(-1); } if (ftruncate(fd, 10000) == -1) { printf("ftruncate failed"); exit(-1); } /* Map shared memory object */ addr = mmap(NULL, 10000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { printf("mmap failed"); exit(-1); } exit(EXIT_SUCCESS); }
如上程序建立一各 10000 字節的共享內存對象:
# gcc pshm_create.c -o pshm_create -lrt # ./pshm_create demo_shm # ls -l /dev/shm/demo_shm -rwxr-xr-x 1 root root 10000 Jun 16 03:34 /dev/shm/demo_shm
將數據複製進一個 POSIX 共享內存對象.
#include<stdio.h> #include<string.h> #include<fcntl.h> #include<sys/mman.h> #include<sys/stat.h> #include <unistd.h> #include <stdlib.h> int main(int argc, char *argv[]) { int fd; size_t len; char *addr; /* Open existing object */ fd = shm_open(argv[1], O_RDWR, 0); if (fd == -1) { printf("shm_open failed"); exit(-1); } len = strlen(argv[2]); /* Resize object to hold string */ if (ftruncate(fd, len) == -1) { printf("ftruncate failed"); exit(-1); } addr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { printf("mmap failed"); exit(-1); } if (close(fd) == -1) { printf("close failed"); exit(-1); } printf("copying %ld bytes\n", (long)len); /* Copy string to shared memory */ memcpy(addr, argv[2], len); exit(EXIT_SUCCESS); }
向 1.3 建立的共享內存對象 demo_shm 寫入數據:
# gcc pshm_write.c -o pshm_write -lrt # ls -l /dev/shm/demo_shm -rwxr-xr-x 1 root root 10000 Jun 16 03:34 /dev/shm/demo_shm # ./pshm_write demo_shm 'hello' copying 5 bytes # ls -l /dev/shm/demo_shm -rwxr-xr-x 1 root root 5 Jun 16 03:46 /dev/shm/demo_shm
從一個 POSIX 共享內存對象中複製數據。
#include<stdio.h> #include<string.h> #include<fcntl.h> #include<sys/mman.h> #include<sys/stat.h> #include <unistd.h> #include <stdlib.h> int main(int argc, char *argv[]) { int fd; char *addr; struct stat sb; /* Open existing object */ fd = shm_open(argv[1], O_RDONLY, 0); if (fd == -1) { printf("shm_open failed"); exit(-1); } /* Use shared memory object size as length argument for mmap() * and as number of bytes to write() */ if (fstat(fd, &sb) == -1) { printf("fstat failed"); exit(-1); } addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { printf("mmap failed"); exit(-1); } if (close(fd) == -1) { printf("close failed"); exit(-1); } write(STDOUT_FILENO, addr, sb.st_size); printf("\n"); exit(EXIT_SUCCESS); }
顯示剛纔寫到共享內存對象 demo_shm 中的字符串:
# gcc pshm_read.c -o pshm_read -lrt # ./pshm_read demo_shm hello
POSIX 共享內存對象具備內核持久性,即它們會持續存在直到被顯示刪除或系統重啓。當再也不須要一個共享內存對象時就應該使用 shm_unlink() 刪除它。
#include <sys/mman.h> int shm_unlink(const char *name); Returns 0 on success, or -1 on error Link with -lrt.
shm_unlink() 函數會刪除經過 name 指定的共享內存對象。刪除一個共享內存對象不會影響對象的既有映射(它會保持有效直到相應的進程調用 munmap() 或終止),但會阻止後續的 shm_open() 調用打開這個對象。一旦全部進程都接觸映射這個對象,對象就會刪除,其中的內容會丟失。
#include <fcntl.h> #include <sys/mman.h> #include <stdlib.h> #include <stdio.h> int main(int argc, char *argv[]) { if (shm_unlink(argv[1]) == -1) { printf("shm_unlink failed"); exit(-1); } exit(EXIT_SUCCESS); }
刪除上面建立的共享內存對象 demo_shm:
# gcc pshm_unlink.c -o pshm_unlink -lrt # ./pshm_unlink demo_shm