linux进程间通信:POSIX 共享内存
文章目錄
- 思維導圖
- 通信原理
- 優勢
- POSIX 共享內存 編程接口
- 編程案例
思維導圖
之前學習過sysemV 的共享內存的實現及使用原理,參考linux進程間通信:system V 共享內存
POSIX 同樣提供共享內存的接口,基本原理和system V的共享內存是一樣的。
通信原理
- 多個進程共享物理內存的同一塊區域(通常稱之為“段”:segment)
- 拋棄了內核態消息轉存處理的過程,讓兩個進程直接通過一塊內存進行通信
我們普通的像PIPE,FIFO,消息隊列等的通信方式如下圖:
這種方式的通信不論讀寫,都需要內核態(系統調用 read,write,pipe,mkfifo,msgget,msgsnd,msgrcv等)的介入,而且都需要經過數據從虛擬地址空間到物理地址空間的拷貝。
而共享內存的通信方式則都避免了以上的通信問題,直接為兩個進程開辟相同的內存空間進行數據交互。
優勢
- 減少了內存的拷貝(從用戶拷貝到內核,從內核拷貝到用戶)
- 減少了2次系統調用(系統調用比較消耗性能,因為CPU處理系統調用時需要從用戶態切換到內核態),提高了系統性能
POSIX 共享內存 編程接口
關于共享內存的接口詳細使用就不一一描述,可以通過man shm_open這種類似的方式查看具體如何使用接口
//創建共享內存
int shm_open(const char *name, int oflag, mode_t mode);
//當共享內存引用計數為0時,刪除共享內存
int shm_unlink(const char *name);
//獲取文件相關的信息,將獲取到的信息放入到statbuf結構體中
int fstat(int fd, struct stat *statbuf);
//調整文件大小,通過裁剪指定字節達到對文件大小的精準控制
int ftruncate(int fd, off_t length);
//將進程空間的文件映射到內存,也可以將進程空間的匿名區域映射到內存
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
//解除文件或者匿名映射
int munmap(void *addr, size_t length);
以上接口包含頭文件 <sys/mman.h> <sys/mman.h>
編程案例
-
共享內存基本使用
shm_read.c共享內存的讀端#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <sys/stat.h> #include <string.h> #include <fcntl.h>#define SHM_NAME "/shm"int main() {int shm_fd;//創建共享內存文件標識符shm_fd = shm_open(SHM_NAME, O_RDWR | O_CREAT, 0666);if (shm_fd == -1) {printf("shm_open failed\n");}//設置共享內存的文件大小ftruncate(shm_fd , 8192);//獲取共享內存文件相關屬性信息,這里獲取的是文件大小struct stat filestat;fstat(shm_fd, &filestat);printf("st_size :%ld\n",filestat.st_size);//映射共享內存,并獲取共享內存的地址char *shm_ptr;shm_ptr = (char*)mmap(NULL,filestat.st_size,\PROT_READ|PROT_WRITE,MAP_SHARED,shm_fd,0);close(shm_fd);//獲取共享內存地址中的內容并打印,最后再解除映射,刪除共享內存printf("pid %d:%s\n",getpid(),shm_ptr);munmap(shm_ptr, filestat.st_size);shm_unlink(SHM_NAME);return 0; }shm_write.c共享內存的寫端#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <sys/stat.h> #include <string.h> #include <fcntl.h>#define SHM_NAME "/shm"int main() {int shm_fd;//創建和讀端相同的文件標識shm_fd = shm_open(SHM_NAME, O_RDWR | O_CREAT, 0666);if (shm_fd == -1) {printf("shm_open failed\n");}ftruncate(shm_fd , 8192);struct stat filestat;fstat(shm_fd, &filestat);printf("st_size :%ld\n",filestat.st_size);char *shm_ptr;shm_ptr = (char*)mmap(NULL,filestat.st_size,\PROT_READ|PROT_WRITE,MAP_SHARED,shm_fd,0);close(shm_fd);//向共享內存中寫入數據,這里利用memmove進行內存拷貝寫入char buf[] = "hello world";memmove(shm_ptr,buf,sizeof(buf));printf("pid %d:%s\n",getpid(),shm_ptr);//寫入完成后解除映射munmap(shm_ptr, filestat.st_size);return 0; }編譯
gcc shm_read.c -o read -lrtgcc shm_write.c -o write -lrt
輸出如下:
-
共享內存和信號量一同使用,內存訪問的同步
當讀端能夠讀出的前提是讀的時候信號量的value值為1,否則無法讀出
同樣寫的時候對信號量進行v操作,將信號量的value值加1,為讀提供同步條件實現如下
讀端sem_shm_read.c#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <sys/stat.h> #include <semaphore.h> #include <string.h> #include <fcntl.h>#define SHM_NAME "/shm" #define SEM_NAME "/memmap_sem"int main() {//增加信號量的初始創建int shm_fd;sem_t *sem;shm_fd = shm_open(SHM_NAME, O_RDWR | O_CREAT, 0666);sem = sem_open(SEM_NAME, O_CREAT, 0666, 0);if (shm_fd == -1 || sem == SEM_FAILED) {printf("open failed\n");_exit(-1);}ftruncate(shm_fd , 8192);struct stat filestat;fstat(shm_fd, &filestat);printf("st_size :%ld\n",filestat.st_size);char *shm_ptr;shm_ptr = (char*)mmap(NULL,filestat.st_size,\PROT_READ|PROT_WRITE,MAP_SHARED,shm_fd,0);close(shm_fd);//讀的時候對信號量做p操作(-1),如果信號量此時為0時則無法讀出sem_wait(sem);printf("pid %d:%s\n",getpid(),shm_ptr);sem_close(sem);//讀完之后刪除共享內存,刪除信號量munmap(shm_ptr, filestat.st_size);shm_unlink(SHM_NAME);sem_unlink(SEM_NAME);return 0; }寫端
shm_write.c#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <sys/stat.h> #include <semaphore.h> #include <string.h> #include <fcntl.h>#define SHM_NAME "/shm" #define SEM_NAME "/memmap_sem"int main() {int shm_fd;sem_t *sem;shm_fd = shm_open(SHM_NAME, O_RDWR | O_CREAT, 0666);sem = sem_open(SEM_NAME, O_CREAT, 0666, 0);if (shm_fd == -1 || sem == SEM_FAILED) {printf("open failed\n");_exit(-1);}ftruncate(shm_fd , 8192);struct stat filestat;fstat(shm_fd, &filestat);printf("st_size :%ld\n",filestat.st_size);char *shm_ptr;shm_ptr = (char*)mmap(NULL,filestat.st_size,\PROT_READ|PROT_WRITE,MAP_SHARED,shm_fd,0);close(shm_fd);char buf[] = "hello world";memmove(shm_ptr,buf,sizeof(buf));printf("pid %d:%s\n",getpid(),shm_ptr);//寫的時候對信號量的值執行v(+1)操作, 方便后續的讀sem_post(sem);sem_close(sem);munmap(shm_ptr, filestat.st_size);return 0; }
總結
以上是生活随笔為你收集整理的linux进程间通信:POSIX 共享内存的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 肩并着肩是哪首歌啊?
- 下一篇: 求一个关于皮肤黑的个性签名。