Linux进程间通信六 Posix 共享内存简介与示例
1. 共享內(nèi)存簡(jiǎn)介
共享內(nèi)存主要用于不同進(jìn)程之間相互通信,因?yàn)椴僮鞯氖峭粔K地址,不需要內(nèi)核和用戶層之間數(shù)據(jù)拷貝,屬于最快的進(jìn)程間通信方式,不過(guò),為了防止讀寫(xiě)沖突,一般需要額外的同步手段。之前介紹了SystemV共享內(nèi)存的使用方式,今天介紹下Posix共享內(nèi)存。Posix 共享內(nèi)存API主要有這幾個(gè),shm_open,用于獲取或者創(chuàng)建一個(gè)共享內(nèi)存文件描述符,ftruncate,用于設(shè)置共享內(nèi)存的大小,新建的共享內(nèi)存大小為0,mmap,用于將共享內(nèi)存文件映射到進(jìn)程的虛擬地址空間,其實(shí)共享內(nèi)存真正核心的工作主要在于mmap,不過(guò)mmap是另外一個(gè)話題,暫時(shí)不討論。munmap,和mmap作用相反。shm_unlink,移除共享內(nèi)存。close關(guān)閉shm_open獲取的文件描述符,通常mmap之后就可以關(guān)閉了。fstat獲取共享內(nèi)存的信息,比如大小。下面介紹下相關(guān)API接口
2. API接口
2.1 創(chuàng)建共享內(nèi)存
#include <sys/mman.h> #include <sys/stat.h> /* For mode constants */ #include <fcntl.h> /* For O_* constants *//** * @brief 創(chuàng)建或獲取已存在的共享內(nèi)存 * * @params name 共享內(nèi)存名字,以斜杠開(kāi)頭'/',不超過(guò)NAME_MAX(255)字符 * @params oflag O_RDONLY| O_RDWR| O_CREAT| O_EXCL| O_TRUNC * @params mode 設(shè)置一些權(quán)限,通常使用0即可 * * @returns 成功返回文件描述符,失敗返回-1 **/int shm_open(const char *name, int oflag, mode_t mode);2.2 設(shè)置共享內(nèi)存大小
#include <unistd.h> #include <sys/types.h>/** * @brief 修改fd的大小 * * @returns 成功返回0,失敗返回-1 **/int ftruncate(int fd, off_t length);2.3 查詢共享內(nèi)存文件大小
#include <unistd.h> #include <sys/types.h>/** * @brief 查詢fd的信息 * @param fd 要查詢的文件描述符 * @param buf 用于保存查詢結(jié)果的buffer * @returns 成功返回0,失敗返回-1 **/struct stat {dev_t st_dev; /* ID of device containing file */ino_t st_ino; /* inode number */mode_t st_mode; /* protection */nlink_t st_nlink; /* number of hard links */uid_t st_uid; /* user ID of owner */gid_t st_gid; /* group ID of owner */dev_t st_rdev; /* device ID (if special file) */off_t st_size; /* total size, in bytes */blksize_t st_blksize; /* blocksize for file system I/O */blkcnt_t st_blocks; /* number of 512B blocks allocated */time_t st_atime; /* time of last access */time_t st_mtime; /* time of last modification */time_t st_ctime; /* time of last status change */ };int fstat(int fd, struct stat *buf);2.4?映射共享內(nèi)存
#include <sys/mman.h>/** * @brief 映射共享內(nèi)存到進(jìn)程自身虛擬地址空間 * * @params addr 映射到的地址,通常設(shè)置為NULL,表示內(nèi)核自己選擇合適地址。 * @params length 映射的共享內(nèi)存大小 * @params prot 保護(hù)標(biāo)志位,可選PROT_EXEC| PROT_READ| PROT_WRITE| PROT_NONE * @params flags 可選 * MAP_SHARED,共享模式,修改對(duì)其它進(jìn)程可見(jiàn) * MAP_PRIVATE 私有映射,對(duì)共享內(nèi)存的修改對(duì)其它進(jìn)程不可見(jiàn)。 * @params fd 被映射的共享內(nèi)存文件描述符 * @params offset 文件偏移值,通常填0 * @returns 成功返回共享內(nèi)存地址,失敗返回-1 **/void *mmap(void *addr, size_t length,int prot, int flags ,int fd, off_t offset);/** * @brief 刪除mmap的映射 * * @params addr 映射到的地址 * @params length 映射的共享內(nèi)存大小 * @returns 成功返回0址,失敗返回-1 **/int munmap(void *addr, size_t length);2.5 刪除共享內(nèi)存
#include <sys/mman.h> #include <sys/stat.h> /* For mode constants */ #include <fcntl.h> /* For O_* constants *//** * @brief 刪除共享內(nèi)存,只有當(dāng)所有進(jìn)程都取消映射后才銷(xiāo)毀它 * * @params name 共享內(nèi)存名字 * * @returns 成功返回0,失敗返回-1 **/int shm_unlink(const char *name);# 編譯加上 -lrt選項(xiàng) Link with -lrt.3. 共享內(nèi)存示例
這里僅簡(jiǎn)單讀寫(xiě),沒(méi)有考慮同步。
3.1 寫(xiě)共享內(nèi)存
#include <sys/mman.h> #include <sys/stat.h> /* For mode constants */ #include <fcntl.h> /* For O_* constants */ #include <error.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/mman.h> #include <string.h>#define SHM_NAME "/shm0" #define SHM_SIZE 4096int main(int argc, char** argv) {if (argc < 2){printf("Usage: ./shm_write msg\n");return -1;}// 創(chuàng)建或打開(kāi)已存在的共享內(nèi)存int shm_fd = shm_open(SHM_NAME, O_RDWR|O_CREAT, 0);if (shm_fd == -1){perror("shm_open error");return -1;}// 設(shè)置共享內(nèi)存大小if (ftruncate(shm_fd, SHM_SIZE)){perror("ftruncate error");return -1;}// 映射共享內(nèi)存char* buffer = (char *)mmap(NULL, SHM_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, shm_fd, 0);if (buffer == (char *)MAP_FAILED){perror("mmap error");return -1;}// 關(guān)閉共享內(nèi)存文件描述符,并不影響映射close(shm_fd);// 寫(xiě)共享內(nèi)存strncpy(buffer, argv[1], strlen(argv[1]));// 刪除共享內(nèi)存//shm_unlink(shm_fd);return 0; }3.2 讀共享內(nèi)存
#include <sys/mman.h> #include <sys/stat.h> /* For mode constants */ #include <fcntl.h> /* For O_* constants */ #include <error.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/mman.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h>#define SHM_NAME "/shm0" #define SHM_SIZE 4096int main() {// 創(chuàng)建或打開(kāi)共享內(nèi)存int shm_fd = shm_open(SHM_NAME, O_RDWR|O_CREAT, 0);if (shm_fd == -1){perror("shm_open error");return -1;}// 獲取共享內(nèi)存大小,讀取的時(shí)候要用struct stat stat={0};if (fstat(shm_fd, &stat)){perror("fstat error");return -1;}// 映射共享內(nèi)存,大小為上一步獲取的大小char* buffer = (char*)mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, shm_fd, 0);if (buffer == (char *)MAP_FAILED){perror("mmap error");return -1;}// 關(guān)閉文件描述符close(shm_fd);// 讀取共享內(nèi)存printf("Read Msg:%s\n", buffer);// 刪除共享內(nèi)存shm_unlink(SHM_NAME);return 0; }3.3 編譯&運(yùn)行
default:gcc -o shm_read shm_read.c -lrtgcc -o shm_write shm_write.c -lrt clean:rm -rf shm_write shm_read4. 參考文檔
https://www.man7.org/linux/man-pages/man7/mq_overview.7.html
================================================================================================
Linux應(yīng)用程序、內(nèi)核、驅(qū)動(dòng)、后臺(tái)開(kāi)發(fā)交流討論群(745510310),感興趣的同學(xué)可以加群討論、交流、資料查找等,前進(jìn)的道路上,你不是一個(gè)人奧^_^。...
?
?
總結(jié)
以上是生活随笔為你收集整理的Linux进程间通信六 Posix 共享内存简介与示例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 苹果开机进u盘启动怎么办 苹果电脑如何从
- 下一篇: mysql 慢查询 定位过程,和orde