目錄
一、什么是共享內存?
二、共享內存的特點
優點
缺點
三、使用共享內存的基本函數
?1、創建共享內存shmget()
2、掛接共享內存shmat
3、脫離掛接shmdt
?4、共享內存控制shmctl
?5.查看和刪除共享內存
comm.hpp
server.cc?
Client.cc?
Makefile
一、什么是共享內存?
共享內存(Shared Memory)是一種高效的?進程間通信(IPC)機制?,允許多個進程直接訪問同一塊物理內存區域,實現數據的快速交換。它是IPC中速度最快的方式,因為共享內存方式的通信沒有中間過程,而管道、消息隊列等方式則需要將數據通過中間機制進行轉換。
?共享內存的原理如上圖所示,主要分為兩部(創內存、掛接):
1.進程在物理內存上開辟一塊空間,這塊空間稱為共享內存。
2.不同進程將這塊空間掛接到自己的進程地址空間中。
3.進程通過虛擬地址和頁表的映射找到共享內存,然后對共享內存進行讀寫數據。
二、共享內存的特點
優點
- ?高效性?:共享內存是所有進程間通信方式中速度最快的,因為所有進程共享同一塊內存,訪問共享內存區域和訪問進程獨有的內存區域一樣快,并不需要通過系統調用或者其它需要切入內核的過程來完成。
- ?直接訪問?:避免了數據的各種不必要的復制,數據直接寫到內存,不用若干次數據拷貝。
- ?靈活性?:不像匿名管道那樣要求通信的進程有一定的父子關系。
缺點
- ?缺乏同步機制?:系統內核沒有對訪問共享內存進行同步,必須提供自己的同步措施。例如,在數據被寫入之前不允許進程從共享內存中讀取信息、不允許兩個進程同時向同一個共享內存地址寫入數據等。
- ?生命周期?:共享內存的生命周期隨內核,即如果用戶不使用系統調用釋放它,直到操作系統關機之前它會一直存在。
- ?管理復雜性?:需要額外的同步機制(如信號量、互斥鎖)保證數據一致性。
三、使用共享內存的基本函數
?1、創建共享內存shmget()
int shmget(key_t key, size_t size, int shmflg);
參數key:這個共享內存段名字(和消息隊列一樣由ftok獲取)size:共享內存??(自己指定,一般為頁的整數倍)shmflg:由九個權限標志構成,它們的?法和創建?件時使?的mode模式標志是?樣的IPC_CREAT:創建新的共享內存IPC_CREAT|IPC_EXCL|0666:若創建的共享內存存在,報錯IPC_NOWAIT:非阻塞0:如果是打開文件,寫0
返回值:成功返回?個?負整數,即該共享內存段的標識碼;失敗返回-1
2、掛接共享內存shmat
void *shmat(int shmid, const void *shmaddr, int shmflg);
參數shmid: 共享內存標識shmaddr:指定連接的地址(一般默認為NULL,由系統自動分配內存)shmflg:它的兩個可能取值是SHM_RND和SHM_RDONLY(連接操作用于只讀內存)
返回值:成功返回?個指針,指向共享內存第?個節;失敗返回-1
3、脫離掛接shmdt
int shmdt(const void *shmaddr);
參數shmaddr: 由shmat所返回的指針
返回值:成功返回0;失敗返回-1
注意:將共享內存段與當前進程脫離不等于刪除共享內存段
?4、共享內存控制shmctl
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
參數shmid:由shmget返回的共享內存標識碼cmd:將要采取的動作(有三個可取值)buf:指向?個保存著共享內存的模式狀態和訪問權限的數據結構
返回值:成功返回0;失敗返回-1
?5.查看和刪除共享內存
//查看
ipcs -m
//刪除
ipcrm -m id(標識)
共享內存使用案例:
分為兩個進程,客戶端(Client)和服務端(server)?
前提介紹:
.hpp文件的作用與.h文件功能類似
.cc文件等于.cpp文件
comm.hpp
#include <iostream>
#include<stdio.h>
#include <string>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include<string.h>const std::string gpath = "/root/day5_24";
const int gid = 0x6666;
const int gshmsize = 4096;
const int gmode = 0600;
class ShareMemory
{
public:ShareMemory() : _shmid(-1), _ret(nullptr){}~ShareMemory(){}// 創建共享內存int CreateShm(){key_t key = ::ftok(gpath.c_str(), gid);if (key < 0){printf("ftok error\n");return 1;}_shmid = ::shmget(key, gshmsize, IPC_CREAT | IPC_EXCL | gmode);if (_shmid < 0){printf("shmget error\n");return 2;}return _shmid;}// 獲得共享內存void GetShm(){key_t key = ::ftok(gpath.c_str(), gid);if (key < 0){printf("ftok error\n");}_shmid = ::shmget(key, gshmsize, IPC_CREAT|gmode);std::cout << "_shmid: " << _shmid << std::endl;if (_shmid < 0){printf("shmget error\n");}}// 掛地址void AttachShm(){_ret = shmat(_shmid, nullptr, 0);std::cout << "_shmid: " << _shmid << std::endl;}// 去關聯void DetachShm(){int d = shmdt(_ret);if (d == -1){printf("shmdt error\n");return;}printf("shmdt success\n");}// 釋放內存void DeleteShm(){shmctl(_shmid, IPC_RMID, nullptr);}void *getadder(){return _ret;}void ShmMeta(){//}private:int _shmid;void *_ret;
};ShareMemory sm;
server.cc?
#include"time.hpp"
#include "Comm.hpp"
using namespace std;int main()
{sm.CreateShm();sm.AttachShm();// 在此處讀出while(true){char* image=(char*)sm.getadder();std::cout << image << std::endl;sleep(1);}sm.DetachShm();sm.DeleteShm();return 0;
}
Client.cc?
#include "Comm.hpp"
#include"time.hpp"
int main()
{sm.GetShm();sm.AttachShm();// 在此處寫入char*image = (char*)sm.getadder();char i[] = "i am processA";while (true){strcpy(image, i);sleep(1);}sm.DetachShm();return 0;
}
Makefile
SERVER=server
CLIENT=client
CC=g++
SERVER_SRC=Server.cc
Client_SRC=Client.cc.PHONY:all
all:$(SERVER) $(CLIENT)$(SERVER):$(SERVER_SRC)$(CC) -o $@ $^ -std=c++11 -g
$(CLIENT):$(Client_SRC)$(CC) -o $@ $^ -std=c++11 -g.PHONY:clean
clean:rm -f $(SERVER) $(CLIENT)
----------------------------------------------------------------------------------------------------------------------------
本篇介紹到此結束,有問題歡迎給我評論留言。謝謝