一. 共享内存需要用到的系统调用接口
1.ftok
功能:创建一个独一无二的key_t类型的数值(返回值一般做shmget的第一个参数)
原型
key_t ftok(const char *pathname, int proj_id);
参数
pathname:文件路径加文件名
proj_id:整数标识符
返回值:成功:返回key_t值(即IPC 键值)出错:-1,错误原因存于error中
2.shmget
功能:用来创建共享内存
原型
int shmget(key_t key, size_t size, int shmflg);
参数
key:这个共享内存段名字
size:共享内存大小
shmflg:由九个权限标志构成,它们的用法和创建文件时使用的
mode
模式标志是一样的
返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回
-1
int shmid = shmget(key, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666);//666可读可写;
shmat函数
功能:将共享内存连接到进程地址空间
原型
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数
shmid:用户级的共享内存编号(shmget中的key为操作系统级别的共享内存编号)
shmaddr:共享内存要连接到的虚拟地址(非特殊情况一般置为nullptr,由操作系统自行指派)
shmflg: 他的俩个可能的取值IPC_WRONLY和IPC_REONLY前者为只写模式,后者为只读模式
返回值:成功则返回所连接的虚拟地址,失败则返回-1。
shmdt
函数
功能:断开共享内存和虚拟地址之间的联系
原型
int shmdt(const void *shmaddr);
参数
shmaddr:由shmat返回的虚拟地址。
返回值:成功则返回0,失败则返回-1;
shmctl
函数
功能:
用于控制共享内存
原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数
shmid:用户级别的共享内存编号
cmd:要对共享内存执行的操作
buf:输出型参数,指向一个保存着共享内存的模式状态和访问权限的数据结构
代码展示:
#include "my_shm.hpp"
int main()
{
//创建一个公共的key值
key_t key=ftok(PATH_NAME,PROJ_ID);
assert(key!=-1);
cout<<"创建key成功"<<endl;
//获取共享内存的id
int shmid=shmget(key,SHM_SIZE,0);
if(shmid==-1)
{
perror("shmget");
exit(1);
}
cout<<"获取共享内存的id成功"<<endl;
//连接共享内存
char* shmaddr=(char*)shmat(shmid,nullptr,0);
cout<<"连接共享内存成功"<<endl;
//进行进程之间的通信工作
int fd=open("./fifo",O_WRONLY);
while(true)
{
ssize_t s=read(0,shmaddr,SHM_SIZE);
if(s>0)
{
shmaddr[s-1]=0;
signal(fd);
if(strcmp(shmaddr,"quit")==0)
{
cout<<"退出进程之间的通信"<<endl;
break;
}
else
{
cout<<"发送成功"<<endl;
}
}
}
//断开共享内存之间的联系
int n=shmdt(shmaddr);
if(n==-1)
{
perror("shmdt");
exit(1);
}
cout<<"断开进程与共享内存之间的操作成功"<<endl;
return 0;
}
#include "my_shm.hpp"
int main()
{
Init init;
// 创建一个公共的key值
key_t key = ftok(PATH_NAME, PROJ_ID);
assert(key != -1);
cout << "创建key成功" << endl;
// 创建一个共享内存
int shmid = shmget(key, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666);//666可读可写;
if (shmid == -1)
{
perror("shmget");
exit(1);
}
cout << "共享内存创建成功" << endl;
// 连接共享内存
char *shmaddr = (char *)shmat(shmid, nullptr, 0);
cout << "连接共享内存成功" << endl;
// 进行进程之间的通信工作
int fd=my_open("./fifo",O_RDONLY);
while (true)
{
my_wait(fd);
printf("%s\n", shmaddr);
if (strcmp(shmaddr, "quit") == 0)
{
cout << "退出通信" << endl;
break;
}
sleep(1);
}
// 断开共享内存之间的联系
int n = shmdt(shmaddr);
if (n == -1)
{
perror("shmdt");
exit(1);
}
cout << "断开进程与共享内存之间的操作成功" << endl;
// 删除共享内存
n = shmctl(shmid, IPC_RMID, nullptr);
if (n == -1)
{
perror("shmctl");
exit(1);
}
cout << "删除共享内存成功" << endl;
return 0;
}
#pragma once
#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cassert>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// #include "Log.hpp"
using namespace std; // 不推荐
#define PATH_NAME "/home/xiaon"
#define PROJ_ID 0x66
#define SHM_SIZE 4096 // 共享内存的大小,最好是页(PAGE: 4096)的整数倍
class Init
{
public:
Init()
{
umask(0);
int n=mkfifo("./fifo", 0666);
if(n==-1)
{
perror("mkfifo");
exit(1);
}
cout<<"已创建管道"<<endl;
}
~Init()
{
int n=unlink("./fifo");
if(n==-1)
{
perror("nulink");
exit(1);
}
cout<<"已删除管道文件"<<endl;
}
};
int my_open(char* pathname,int cmd)
{
int fd=open(pathname,cmd);
if(fd==-1)
{
perror("open");
exit(1);
}
cout<<"打开管道文件成功"<<endl;
return fd;
}
void my_close(int fd)
{
int n=close(fd);
if(n==-1)
{
perror("close");
exit(1);
}
cout<<"关闭管道文件成功"<<endl;
}
void my_wait(int fd)
{
cout<<"等待信号中"<<endl;
uint32_t command;
ssize_t s=read(fd,&command,sizeof(command));
assert(s==4);
}
void signal(int fd)
{
cout<<"唤醒中"<<endl;
uint32_t command=1;
ssize_t s=write(fd,&command,sizeof(command));
assert(s==4);
}