共享内存(Shared Memory)是一种多个进程之间共享某些内存区域以进行通信的机制。这些共享的内存区域可以被多个进程访问,从而实现对进程间数据的快速交换。共享内存是最快的IPC(Inter-Process Communication,进程间通信)方式,它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程对共享内存中数据的更新。这种通信方式需要依靠某种同步机制(如信号量等)来实现进程之间的同步和互斥。
要实现共享内存:
第一步是创建一个key用于标记共享内存(通信者约定好ftok()的参数函数会返回一个相同的key)
第二部要创建共享内存,参数分别是key(上边ftok生成的key)size(共享内存的大小,推荐4KB)第三个参数是打开方式(如果你是创建就IPC_CREAT | IPC_EXCL,如果你是打开共享内存就IPC_CREAT)。
第三部关联共享内存(第一个参数传入shmget的反回值,第二个参数传nullptr表示系统帮你选择一块地址空间,第三个参数传0表示默认以读写方式打开,返回值是这块空间的起始地址,默认大小是shmget传的size)
实现自己的通信逻辑。。。
第四步取消关联:shmdt传入shmat的返回值
第五步关闭共享内存:cmd选择 IPC_RMID,buf可以传nullptr
具体实现代码:
通过对管道的read,write去控制共享内存的读写(共享内存本身不会协同)
com.hpp
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <iostream>
#include <cstring>
#include "fifo.hpp"
using namespace std;
#define shm_size 4096
#define path "/root/110"
#define id 0x66
string TO_HEX(int num)
{
char buffer[1024];
snprintf(buffer,sizeof(buffer),"0X%x",num);
return buffer;
}
key_t creatKeyorDie(const char* pathname,int proj_id)
{
key_t n = ftok(pathname,proj_id);
if(n==-1)
{
cerr<<"creatKey fail"<<endl;
}
return n;
}
int creatShmorDie(key_t key,size_t size,int shmflg)
{
int n = shmget(key,size,shmflg);
if(n==-1)
{
cerr<<"shmget fail"<<endl;
exit(1);
}
return n;
}
int creatShm(key_t key,size_t size)
{
//IPC_CREAT
//IPC_EXC
return creatShmorDie(key,size,IPC_CREAT|IPC_EXCL);
}
int getShm(key_t key,size_t size)
{
return creatShmorDie(key,size,IPC_CREAT);
}
void DeleteShm(int shmid)
{
int n = shmctl(shmid,IPC_RMID,nullptr);
if(n==-1)
{
cerr<<"DleteShm fail"<<endl;
}
else
{
std::cout << "shmctl delete shm success, shmid: " << shmid << std::endl;
}
}
void* shmAttach(int shmid)
{
void* addr = shmat(shmid,nullptr,0);
if((long long int)addr==-1)
{
cerr<<"Attach fail"<<endl;
return nullptr;
}
return addr;
}
void shmDetach(void *addr)
{
int n = shmdt(addr);
if (n < 0)
{
std::cerr << "shmdt error" << std::endl;
}
}
fifo.hpp
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#define Path "./fifo"
class Fifo
{
public:
Fifo(const std::string& path = Path):_path(path)
{
umask(0);
int n = mkfifo(_path.c_str(),0666);
if(n==-1)
{
std::cerr<<"mkfifo fail"<<errno<<":"<<strerror(errno)<<std::endl;
}
else
{
std::cout << "mkfifo success" << std::endl;
}
}
~Fifo()
{
int n = unlink(_path.c_str());
if(n==-1)
{
std::cerr<<"unlink fail"<<errno<<":"<<strerror(errno)<<std::endl;
}
else
{
std::cout << "unlink success" << std::endl;
}
}
private:
std::string _path;
};
class Sync
{
public:
Sync():wfd(-1),rfd(-1){}
~Sync(){}
void openReadOrDie()
{
rfd = open(Path, O_RDONLY);
if (rfd < 0)
exit(1);
}
void openWriteOrDie()
{
wfd = open(Path, O_WRONLY);
if (wfd < 0)
exit(1);
}
bool wait()
{
char c;
int n = read(rfd,&c,1);
if(n==1)
{
return true;
}
else
{
return false;
}
}
void wakeup()
{
char c;
int n = write(wfd,&c,1);
if(n==1)
std::cout<<"wakeup"<<std::endl;
}
private:
int wfd;
int rfd;
};
shm_client.cc
#include "com.hpp"
int main()
{
key_t key = creatKeyorDie(path,id);
cout<<"key_t:"<<TO_HEX(key)<<endl;
int shmid = getShm(key,shm_size);
cout<<"shmid:"<<shmid<<endl;
char* buffer = (char*)shmAttach(shmid);
cout << "Attach shm success, addr: " << TO_HEX((uint64_t)buffer) << std::endl;
memset(buffer,0,sizeof(buffer));
Sync syn;
syn.openWriteOrDie();
for(int i = 'a';i < 'z';i++)
{
syn.wakeup();
buffer[i-'a'] = i;
sleep(1);
}
shmDetach(buffer);
return 0;
}
shm_server.cc
#include "com.hpp"
int main()
{
// 1. 获取key
key_t key = creatKeyorDie(path,id);
std::cout << "key: " << TO_HEX(key) << std::endl;
// sleep(2);
// 2. 创建共享内存
int shmid = creatShm(key, shm_size);
std::cout << "shmid: " << shmid << std::endl;
// sleep(2);
// ShmDebug(shmid);
// 4. 将共享内存和进程进行挂接(关联)
char *addr = (char *)shmAttach(shmid);
std::cout << "Attach shm success, addr: " << TO_HEX((uint64_t)addr) << std::endl;
Fifo fifo;
Sync syn;
syn.openReadOrDie();
// 可以进行通信了
for(;;)
{
if(!syn.wait())
break;
sleep(1);
cout << "shm content: " << addr << std::endl;
}
shmDetach(addr);
// 3. 删除共享内存
DeleteShm(shmid);
return 0;
}
下面是两条命令用于查看系统中的共享内存和删除共享内存:
# ipcs -a
------ Message Queues --------
key msqid owner perms used-bytes messages
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
------ Semaphore Arrays --------
key semid owner perms nsems
ipcrm -m shmid//你要删除的共享内存的id