Linux进程间通信一 System V 共享内存简介与示例
目錄
1. System V共享內(nèi)存簡介
2. API介紹
2.0 key_t和標(biāo)識符
2.1? 創(chuàng)建system v共享內(nèi)存
2.2 映射共享內(nèi)存并使用
2.3?取消共享內(nèi)存映射
2.4?控制共享內(nèi)存
3. 實例
3.1 共享內(nèi)存寫示例
3.2 共享內(nèi)存讀示例
4. 運行
5.?注意事項
6. 參考資料
1. System V共享內(nèi)存簡介
System V IPC通常指的是以下三種:
System V IPC最早是在上世紀(jì)70年代末由貝爾實驗室開發(fā)出來,三種IPC在實現(xiàn)架構(gòu)、使用方式上有很多相同之處,比如內(nèi)核實現(xiàn)里共用了ipc_perm權(quán)限管理結(jié)構(gòu)體,使用方式上都包括基本的xxxget,xxxctl等等。今天主要介紹下System V 共享內(nèi)存的使用方式。共享內(nèi)存作為IPC通信中最快的一種,之所以快是因為一旦創(chuàng)建成功,后續(xù)操作無需內(nèi)核拷貝數(shù)據(jù)以及系統(tǒng)調(diào)用,通信雙方可以直接操作共享內(nèi)存來通信。因為開發(fā)出來比較早,所以存在一些缺陷,所以就有了Posix IPC的產(chǎn)生,不過這是后話,在此不提。首先看下共享內(nèi)存的接口。
2. API介紹
2.0 key_t和標(biāo)識符
System V IPC對象通過標(biāo)識符來區(qū)分,該標(biāo)志符具有系統(tǒng)唯一性,是操作系統(tǒng)內(nèi)的全局變量。生成SystemV IPC對象的Get函數(shù)需要一個key_t參數(shù),這是一個整型變量,用于對應(yīng)一個標(biāo)識符。該標(biāo)識符通常有三種方法生成:
?
2.1? 創(chuàng)建system v共享內(nèi)存
可以使用ipcs | ipcrm | ipcmk 查看、刪除和創(chuàng)建共享內(nèi)存
#include <sys/ipc.h> #include <sys/shm.h>/** * @brief 創(chuàng)建共享內(nèi)存ID * * @params key 與shm_id關(guān)聯(lián)的key,三種生成方式,包括IPC_PRIVATE,注意key和shm_id不是綁定關(guān)系,相同的key產(chǎn)生的標(biāo)識符不一定相同。 * @params size 共享內(nèi)存的大小,必須是正整數(shù)。 * @params shmflg 標(biāo)志位和權(quán)限控制標(biāo)志位,可以多個用or運算。IPC_CREAT、 IPC_EXCL * * @returns 成功返回shmid,失敗返回-1 */int shmget(key_t key, size_t size, int shmflg);根據(jù)標(biāo)志位的不同,有如下幾種情況:
| oflag參數(shù) | key不存在 | key已經(jīng)存在 |
| 無特殊標(biāo)志位 | 返回-1 | 返回標(biāo)識符 |
| IPC_CREAT | 返回新建標(biāo)識符 | 返回已有標(biāo)識符 |
| IPC_CREAT|IPC_EXCL | 返回新建標(biāo)識符 | 返回-1 |
?
2.2 映射共享內(nèi)存并使用
使用共享內(nèi)存前需要將其映射到經(jīng)常自身地址空間,之后就可以像malloc分配的內(nèi)存一樣使用了
#include <sys/types.h> #include <sys/shm.h>/** * @brief 映射共享內(nèi)存到進(jìn)程指定地址 * * @params shmid 共享內(nèi)存標(biāo)識符 * @params shmaddr 映射的地址,為NULL則內(nèi)核自動選擇合適的地址,非空并且設(shè)置SHM_RND標(biāo)志位,則自動對齊,如果沒有此標(biāo)志位并且不對齊,報錯。 * @params shmflg 可以設(shè)置SHM_RND、SHM_REMAP,SHM_RDONLY * 如果映射的地址已經(jīng)有了映射,可以設(shè)置SHM_REMAP標(biāo)志位重新映射,否則報錯。 * 如果地址不對齊,可以設(shè)置SHM_RND標(biāo)志位,此時內(nèi)核自動找到符合符合要求的地址,否則報錯。 * * @returns 成功返回映射地址,可以像malloc返回的地址那樣操作,失敗返回 (void *) -1 */void *shmat(int shmid, const void *shmaddr,int shmflg);2.3?取消共享內(nèi)存映射
#include <sys/types.h> #include <sys/shm.h>/** * @brief 取消共享內(nèi)存映射 * * @params shmaddr shmat返回的共享內(nèi)存地址 * * 只是減少共享內(nèi)存的引用計數(shù)并未實際刪除共享內(nèi)存 * * @returns 成功返回0,失敗返回 -1 */int shmdt(const void *shmaddr);2.4?控制共享內(nèi)存
#include <sys/ipc.h> #include <sys/shm.h>struct shmid_ds {struct ipc_perm shm_perm; /* 所有權(quán)及權(quán)限 */size_t shm_segsz; /* 共享內(nèi)存大小 (bytes) */time_t shm_atime; /* 上次shmat時間 */time_t shm_dtime; /* 上次shmdt時間 */time_t shm_ctime; /* 上次修改時間 */pid_t shm_cpid; /* 創(chuàng)建進(jìn)程皮帶 */pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */shmatt_t shm_nattch; /* 當(dāng)前shmat進(jìn)程數(shù)量 */... };/** * @brief 取消共享內(nèi)存映射 * * @params shmid 共享內(nèi)存標(biāo)識符 * @params cmd 控制命令,IPC_STAT, IPC_SET, IPC_RMID, SHM_LOCK, SHM_UNLOCK * @params buf 緩存 * IPC_STAT 獲取對應(yīng)共享內(nèi)存信息,存到buf緩存里。 * IPC_SET 只能修改shm_perm里面的uid,gid及mode * IPC_RMID 刪除共享內(nèi)存,只有引用計數(shù)為0才真正刪除 * SHM_LOCK 阻止共享內(nèi)存被替換出去 * SHM_UNLOCK 和SHM_LOCK相反 * * @returns 成功返回0,失敗返回 -1 */int shmctl(int shmid, int cmd, struct shmid_ds *buf);3. 實例
3.1 共享內(nèi)存寫示例
/* ** Name: shm_write.c ** Desc: 共享內(nèi)存寫端 ** Author: masonf ** Date: 2020-06-02 */#include <sys/ipc.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <sys/shm.h> #include <sys/types.h> #include <unistd.h>// 消息結(jié)構(gòu)體 typedef struct{char content[128]; } msg;main(int argc, char** argv) {int shm_id,i;key_t key;msg *pMsg;if (argc < 2){printf("invalid argument\n");return ;}// key簡單寫死key = 9999;// 創(chuàng)建共享內(nèi)存shm_id=shmget(key,4096,IPC_CREAT);if(shm_id == -1){perror("shmget error");return;}// 映射共享內(nèi)存到進(jìn)程地址空間pMsg=(msg*)shmat(shm_id, NULL, 0);if (pMsg == (void *)-1){perror("shmat error");return ;}// 寫數(shù)據(jù)到共享內(nèi)存memcpy(pMsg->content, argv[1], strlen(argv[1]));// 取消共享內(nèi)存映射,并沒有刪除共享內(nèi)存if(shmdt(pMsg) == -1){perror(" detach error ");}return ; }3.2 共享內(nèi)存讀示例
/* ** Name: shm_read.c ** Desc: 共享內(nèi)存讀端 ** Author: masonf ** Date: 2020-06-02 */#include <sys/ipc.h> #include <stdio.h> #include <sys/shm.h> #include <errno.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> typedef struct{char content[128]; } msg;void main(int argc, char** argv) {int shm_id,i;key_t key;msg *pMsg = NULL;// 使用固定值key = 9999;// 存在則直接返回共享內(nèi)存shm_id = shmget(key, 4096, IPC_CREAT); if(shm_id == -1){perror("shmget error");return;}// 映射共享內(nèi)存到進(jìn)程自身地址空間pMsg = (msg*)shmat(shm_id,NULL,0);if (pMsg == NULL){printf("shmat error, errno:%d", errno);return ;}printf("Get Msg from shm_id:%s\n", pMsg->content);// 取消共享內(nèi)存映射if(shmdt(pMsg) == -1){perror(" detach error ");}return; }4. 運行
5.?注意事項
- shmmax? 單個共享內(nèi)存塊最大字節(jié)數(shù)
- shmmnb? 共享內(nèi)存空間最小字節(jié)數(shù)
- shmmni? 系統(tǒng)最多可以創(chuàng)建的共享內(nèi)存數(shù)量
- shmseg? 單個進(jìn)程最多可以映射的共享內(nèi)存數(shù)量
- shmall? ?系統(tǒng)可供使用的共享內(nèi)存大小
6. 參考資料
1.?https://linux.die.net/man/2/shmctl
https://linux.die.net/man/2/shmget
2. 《Linux環(huán)境編程 從應(yīng)用到內(nèi)核》
3. 《Unix網(wǎng)絡(luò)編程 卷二 進(jìn)程間通信》
?
================================================================================================
Linux應(yīng)用程序、內(nèi)核、驅(qū)動、后臺開發(fā)交流討論群(745510310),感興趣的同學(xué)可以加群討論、交流、資料查找等,前進(jìn)的道路上,你不是一個人奧^_^。...
?
?
總結(jié)
以上是生活随笔為你收集整理的Linux进程间通信一 System V 共享内存简介与示例的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: w7系统不能显示u盘启动不了怎么办 解决
- 下一篇: Linux进程间通信二 System V