一、什么是共享內存
?共享內存區是最快的(進程間通信)IPC形式。一旦這樣的內存映射到共享它的進程的地址空間,這些進程間數據傳遞不再涉及到內核,換句話說是進程不再通過執行進入內核的系統調用來傳遞彼此的數據。注意:共享內存沒有進行同步與互斥!共享內存不會自動銷毀,要手動銷毀。
二、?共享內存的原理圖
三、共享內存的接口(什么用)
ftok
功能:生成一個key,key是shmget第一個參數,這個key是一個約定的數,讓不同的進程通過key找到同一份資源,不用再進入內存查找。
頭文件
#include <sys/types.h>
#include <sys/ipc.h>
原型
key_t ftok(const char *pathname, int proj_id);
參數pathname:一個路徑字符串,可以隨便給
proj_id:一個int數據,可以隨便給
返回值:返回key
shmget
功能:用來創建共享內存
頭文件
#include <sys/ipc.h>
#include <sys/shm.h>
原型
int shmget(key_t key, size_t size, int shmflg);
參數
key:這個共享內存段名字,這個key是一個約定的數,讓不同的進程通過key找到同一份資源
size:共享內存的大小(一般取 n * 1024)
shmflg:由九個權限標志構成,它們的用法和創建文件時使用的mode模式標志是一樣的主要用這兩個:
IPC_EXCL:不存在共享內存就創建,存在就使用現有的
IPC_EXCL:不存在共享內存就創建,存在就報錯,保證創建的共享內存是新的
返回值:成功返回一個非負整數,即該共享內存段的標識碼;失敗返回-1
shmat
功能:將共享內存段連接到進程地址空間
頭文件
?#include <sys/types.h>
?#include <sys/shm.h>
原型
void *shmat(int shmid, const void *shmaddr, int shmflg);
參數
shmid: 共享內存標識,shmget的返回值
shmaddr:指定連接的地址
shmflg:它的兩個可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一個指針,指向共享內存第一個節;失敗返回-1說明:
shmaddr為NULL,核心自動選擇一個地址
shmaddr不為NULL且shmflg無SHM_RND標記,則以shmaddr為連接地址。
shmaddr不為NULL且shmflg設置了SHM_RND標記,則連接的地址會自動向下調整為SHMLBA的整數倍。公式:shmaddr - (shmaddr % SHMLBA)
shmflg=SHM_RDONLY,表示連接操作用來只讀共享內存
shmdt
功能:將共享內存段與當前進程脫離
頭文件
?#include <sys/types.h>
?#include <sys/shm.h>
原型
int shmdt(const void *shmaddr);
參數
shmaddr: 由shmat所返回的指針
返回值:成功返回0;失敗返回-1
注意:將共享內存段與當前進程脫離不等于刪除共享內存段,刪除共享內存用shmctl
shmctl
功能:用于控制共享內存
頭文件
?#include <sys/ipc.h>
?#include <sys/shm.h>
原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
參數
shmid:由shmget返回的共享內存標識碼
cmd:將要采取的動作(有三個可取值)
- PC STAT 把shmid ds結構中的數據設置為共享內存的當前關聯值
- IPC SET 在進程有足夠權限的前提下,把共享內存的當前關聯值設置為shmid ds數據結構中給出的值
- IPC RMID 刪除共享內存段
buf:指向一個保存著共享內存的模式狀態和訪問權限的數據結構,一般設為nullptr
返回值:成功返回0;失敗返回-1
?四、使用演示
使用代碼創建一個共享內存, 支持兩個進程進行通信
?進程A 向共享內存當中寫 “i am process A”
?進程B 從共享內存當中讀出內容,并且打印到標準輸出
?使用到的linux的一些指令
ipcs -m:查看共享內存的消息
ipcrm -m shmid:刪除共享內存標識碼為shmid的共享內存
監視腳本
while :; do ipcs -m; sleep 1; done
功能:每隔一秒打印一次共享內存消息
shm.hpp
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string>
#include <cstring>
#include <iostream>
#include <unistd.h>using namespace std;const string pathname = "/home/lwj/code11";
const int proj_id = 0x112233;
const int size = 4096;
key_t Getkey()
{int key = ftok(pathname.c_str(), proj_id);if(key < 0){perror("ftok");exit(-1);}return key;
}char* gethex(int x)
{char s[1024];sprintf(s, "0x%x", x);return s;}
processA.cc
#include "shm.hpp"
int main()
{key_t key = Getkey();cout << "獲取key: " << gethex(key) << endl;sleep(10);//獲取shmidint shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0644);cout << "創建shm, 獲取shmid: " << shmid << endl; if(shmid < 0){cerr << "shmget fail" << endl;exit(-1);};sleep(10);//連接shmcout << "連接shm" << endl; char* s = (char*)shmat(shmid, nullptr, 0);sleep(10);//通信cout << "寫消息" << endl;string str = "i am process A";int i = 0;for (auto e : str){s[i] = e;i++;}s[i] = '\0';//斷開shmsleep(10);cout << "斷開shm" << endl; shmdt(s);sleep(10);//銷毀shmcout << "銷毀shm" << endl; shmctl(shmid, IPC_RMID, nullptr);return 0;
}
processB.cc
#include "shm.hpp"
int main()
{key_t key = Getkey();cout << "獲取key: " << gethex(key) << endl;sleep(5);// 獲取shmidint shmid = shmget(key, size, IPC_CREAT);cout << "創建shm, 獲取shmid: " << shmid << endl; if(shmid < 0){cerr << "shmget fail" << endl;exit(-1);}// 連接shmcout << "連接shm" << endl;char *s = (char *)shmat(shmid, nullptr, 0);sleep(5);// 通信cout << "讀消息: " << s << endl;// 斷開shmsleep(10);cout << "斷開shm" << endl;shmdt(s);sleep(10);// 銷毀shmcout << "銷毀shm" << endl;shmctl(shmid, IPC_RMID, nullptr);return 0;
}
Makefile
.PHNOY:all
all:processA processBprocessA:progressA.ccg++ -o $@ $^ -std=c++11
processB:progressB.ccg++ -o $@ $^ -std=c++11.PHONY:clean
clean:rm -f processA processB
演示效果視頻鏈接:
shm演示視頻-CSDN直播