在前面介紹了system v 共享內存的相關知識,如今來稍微看看posix 共享內存 和系列函數。linux
共享內存簡單來講就是一塊真正的物理內存區域,可使用一些函數將這塊區域映射到進程的地址空間進行讀寫,而posix 共享內存與system v 共享內存不一樣的是它是用虛擬文件系統(tmpfs)實現的,已經掛載在/dev/shm 下面。man 7 shm_overviewubuntu
下面來看系列函數,編譯時候加上 -lrt 選項,即鏈接librt 庫 (實時庫)函數
功能:用來建立或打開一個共享內存對象
原型 int shm_open(const char *name, int oflag, mode_t mode);
參數
name:共享內存對象的名字,必須以/打頭,而且後續不能有其它/ ,形如/somename長度不能超過NAME_MAX(255)
oflag:與open函數相似,能夠是O_RDONLY、O_RDWR,還能夠按位或上O_CREAT、O_EXCL、O_TRUNC等。
mode:此參數老是須要設置,若是oflag沒有指定了O_CREAT,能夠指定爲0
返回值:成功返回非負整數文件描述符;失敗返回-1
spa
注意,不存在所謂的shm_close 函數,能夠直接使用close 來關閉文件描述符。.net
功能:修改共享內存對象大小,shm_open不像shmget同樣能夠設置共享內存的大小,但可使用ftruncate 設置大小。
原型 int ftruncate(int fd, off_t length);
參數
fd: 文件描述符
length:長度
返回值:成功返回0;失敗返回-1
code
功能:獲取共享內存對象信息
原型
int fstat(int fd, struct stat *buf);
參數
fd: 文件描述符
buf:返回共享內存狀態
返回值:成功返回0;失敗返回-1
對象
struct stat 能夠參考這裏。blog
相似 shmctl(, IPC_STAT,);
進程
功能:刪除一個共享內存對象
原型 int shm_unlink(const char *name);
參數
name: 共享內存對象的名字
返回值:成功返回0;失敗返回-1
ip
shm_unlink 相似 shmctl(, IPC_RMID, );
功能:將共享內存對象映射到進程地址空間。
原型 void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
參數
addr: 要映射的起始地址,一般指定爲NULL,讓內核自動選擇
len:映射到進程地址空間的字節數
prot:映射區保護方式
flags:標誌
fd:文件描述符
offset:從文件頭開始的偏移量
返回值:成功返回映射到的內存區的起始地址;失敗返回-1
在前面曾經介紹了mmap 函數 將文件映射到進程地址空間的做用,其實它還能夠將共享內存對象映射到進程地址空間,相似shmat的做用,只是傳入的文件描述符fd 是shm_open 返回的。一樣地,解除映射能夠用munmap,相似shmdt 的做用。
下面寫幾個程序來演示一下:
shm_open.c
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include<stdio.h> #include<stdlib.h> #include<sys/ipc.h> #include<sys/types.h> #include<unistd.h> #include<errno.h> #include<fcntl.h> #include<sys/stat.h> #include<sys/mman.h> #define ERR_EXIT(m) \ do { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) int main(void) { int shmid; shmid = shm_open("/xyz", O_CREAT | O_RDWR, 0666); if (shmid == -1) ERR_EXIT("shm_open"); if (ftruncate(shmid, 36) == -1) ERR_EXIT("ftruncate"); struct stat buf; if (fstat(shmid, &buf) == -1) ERR_EXIT("fstat"); printf("size=%ld, mode=%o\n", buf.st_size, buf.st_mode & 0777); close(shmid); return 0; } |
simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./shm_open
size=36, mode=664
simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ls -l /dev/shm/xyz
-rw-rw-r-- 1 simba simba 36 Jun 16 15:01 /dev/shm/xyz
即建立了一個36字節的共享內存段,在/dev/shm 目錄下。
shm_write.c
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#include<stdio.h> #include<stdlib.h> #include<sys/ipc.h> #include<sys/types.h> #include<unistd.h> #include<errno.h> #include<fcntl.h> #include<sys/stat.h> #include<sys/mman.h> #include<string.h> #define ERR_EXIT(m) \ do { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) typedef struct stu { char name[32]; int age; } STU; int main(void) { int shmid; shmid = shm_open("/xyz", O_RDWR, 0); if (shmid == -1) ERR_EXIT("shm_open"); struct stat buf; if (fstat(shmid, &buf) == -1) ERR_EXIT("fstat"); printf("size=%ld, mode=%o\n", buf.st_size, buf.st_mode & 0777); STU *p; p = (STU *)mmap(NULL, buf.st_size, PROT_WRITE, MAP_SHARED, shmid, 0); if (p == MAP_FAILED) ERR_EXIT("mmap"); strcpy(p->name, "test"); p->age = 20; close(shmid); return 0; } |
simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./shm_write
size=36, mode=664
simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ od -c /dev/shm/xyz
0000000 t e s t \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
0000020 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
0000040 024 \0 \0 \0
0000044
使用mmap 將共享內存映射到進程地址空間,將shmid 傳入fd 參數,其他跟文件映射沒什麼區別,od -c查看能夠看到寫入的東西。
shm_read.c
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#include<stdio.h> #include<stdlib.h> #include<sys/ipc.h> #include<sys/types.h> #include<unistd.h> #include<errno.h> #include<fcntl.h> #include<sys/stat.h> #include<sys/mman.h> #include<string.h> #define ERR_EXIT(m) \ do { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) typedef struct stu { char name[32]; int age; } STU; int main(void) { int shmid; shmid = shm_open("/xyz", O_RDONLY, 0); if (shmid == -1) ERR_EXIT("shm_open"); struct stat buf; if (fstat(shmid, &buf) == -1) ERR_EXIT("fstat"); printf("size=%ld, mode=%o\n", buf.st_size, buf.st_mode & 0777); STU *p; p = (STU *)mmap(NULL, buf.st_size, PROT_READ, MAP_SHARED, shmid, 0); if (p == MAP_FAILED) ERR_EXIT("mmap"); printf("name=%s age=%d\n", p->name, p->age); close(shmid); return 0; } |
simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./shm_read
size=36, mode=664
name=test age=20
即讀取到了共享內存的數據,注意,讀取數據後共享內存的數據仍是存在的,除非被覆蓋了。
參考:《UNP》