目录
一.system V共享内存——先让不同的进程看到同一份资源
1.共享内存原理
监控共享内存脚本
3.参数key解释
(1)共享内存存在哪里?
(2)第一个参数key的解释
(3)key一般由用户提供
(4)函数ftok获取key
(5)查看共享内存的命令 ipcs -m,删除共享内存 ipcrm -m (要删的共享内存的shmid)
3.删除共享内存的系统接口 shmctl
4.关联函数shmat、去关联函数shmat
5.我怎么知道,这个共享内存属于存在还是不存在?
一.system V共享内存——先让不同的进程看到同一份资源
进程问通信的前提是:先让不同的进程,看到同一份资源!
1.共享内存原理
监控共享内存脚本
while :; do ipcs -m; sleep 1; echo "############################";done
2.创建/获取 共享内存接口—shmget函数(shared memory get)
①创建共享内存——②删除共享内存
③关联共享内存——④去关联共享内存
这些操作都是OS内部帮我们做,跟进程关联
shmget函数:
创建一个System V 级别的共享内存段
int shmget(key_t key, size_t size, int shmflg);
返回值:成功返回共享内存标识符shmid;错误返回-1
① key:共享内存内核的唯一值(用函数ftok获取key)详解看 3.—>(2)(3)
② size:创建的共享内存大小。(建议设置成为页(4KB)的整数倍,因为操作系统和磁盘IO时基本单位是4KB)
③ shmflg的选项:
IPC_CREAT:创建共享内存,如果已经存在就获取之,不存在就创建之
IPC_ EXCL:不单独使用,必须和IPC_CREAT配合。如果不存在指定的共享内存,创建之;如果存在了,出错返回
IPC_CREAT和IPC_CREAT配合:可以保证,如果shmget函数调用成功—— 一定是一个全新的share memory!(即:如果只是使用IPC_CREAT返回后无法区分是新创建的还是原来就存在的,如果配合使用返回成功,就是新的共享内存;不成功就是原来已经存在的)
shmflg | 0666 :支持异或上权限
3.参数key解释
(1)共享内存存在哪里?
——内核中,内核会给我们维护共享内存的结构!共享内存也要被管理起来! !先描述,再组织!
(2)第一个参数key的解释
想表示存在不存在,就要先有方法标识共享内存的唯一性! !——用key标识
共享内存要被管理
struct shmid_ ds{} 中包含一个结构体 struct ipc_ perm ,这个结构体 struct ipc_ perm 中包含一个成员值叫 key (shmget) (key的作用:共享内存的唯一值! !这个key一般由用户提供)
(3)key一般由用户提供 解释
进程问通信的前提是:先让不同的进程看到同一份资源。如何保证让不同的进程看到同一份共享内存?——做法是:让他们拥有同一个key即可!(用函数ftok获取key)
命名管道——>约定使用同一个文件
共享内存——>约定好使用同一个唯一key,来进行通信的! !
当我们运行完毕创建全新的共享内存的代码后(进程退出),但是第二(n)次的时候,该代码无法运行,告诉我们file存在,即:共享内存是存在的!
systen-V下的共享内存,生命周期是随内核的! !
如果不显示的删除,只能通过kernel (os) 重启来解决!
(4)函数ftok获取key
作用:把一个文件路径和项目标识符转化为一个具有唯一性的数字。
key_t ftok(const char *pathname, int proj_id);
返回值:成功返回生成的key;失败返回-1
例如:
#define PATH_NAME "/home/whb/104"
#define PROJ_ID 0x14
key_t key = ftok(PATH_NAME, PROJ_ID) PROJ_ID随便设一个
(5)查看共享内存的命令 ipcs -m,删除共享内存 ipcrm -m (要删的共享内存的shmid)
perm:权限; nattch:挂接进程数
3.删除共享内存的系统接口 shmctl
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmid:共享内存标识符,表示要删哪一个共享内存。
cmd:选项有常用的IPC_RMID(立即删除,此时buf传nullptr即可删除)(还有IPC_SET设置,IPC_STAT拷贝选项)
例如 shmctl(shmid, IPC_RMID, nullptr);
4.关联函数shmat
shmat (attach-附上),shmdt(detach-拆卸)
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmid:共享内存标识符。shmaddr:设置在地址空间哪个位置,现在设置为nullptr。shmflg:读写,现在设置为0
返回值:成功返回挂接的共享内存地址,出错返回(void*)-1。
返回值和malloc一个意思,你怎么用malloc的空间,你就怎么用共享内存的空间! ( 肯定不能free)
例如:char *str = (char *)shmat(shmid, nullptr, 0);
————————————————————————
shmdt(detach-拆卸)
int shmdt(const void *shmaddr);
shmaddr:就传shmat的返回值。就能去关联
5.我怎么知道,这个共享内存属于存在还是不存在?
只需拿曾经设置过的key和你要设置的key作对比,来确认共享内存是否存在。
6.让进程看到同一份资源的操作
Log.hpp
#pragma once
#include <iostream>
#include <ctime>
std::ostream &Log()
{
std::cout << "Fot Debug |" << " timestamp: " << (uint64_t)time(nullptr) << " | ";
return std::cout;
}
Comm.hpp
(.hpp是声明和定义写在一起的文件)
#pragma once
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cerrno>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define PATH_NAME "/home/whb/104"
#define PROJ_ID 0x14
#define MEM_SIZE 4096
key_t CreateKey()
{
key_t key = ftok(PATH_NAME, PROJ_ID);
if(key < 0)
{
std::cerr <<"ftok: "<< strerror(errno) << std::endl;
exit(1);
}
return key;
}
Makefile
.PHONY:all
all: IpcShmCli IpcShmSer
IpcShmCli:IpcShmCli.cc
g++ -o $@ $^ -std=c++11
IpcShmSer:IpcShmSer.cc
g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
rm -f IpcShmCli IpcShmSer
lpcShmCli.cc
#include "Comm.hpp"
#include "Log.hpp"
#include <unistd.h>
using namespace std;
// 充当使用共享内存的角色
int main()
{
// 创建相同的key值
key_t key = CreateKey();
Log() << "key: " << key << "\n";
// 获取共享内存
int shmid = shmget(key, MEM_SIZE, IPC_CREAT);
if (shmid < 0)
{
Log() << "shmget: " << strerror(errno) << "\n";
return 2;
}
// 挂接
char *str = (char*)shmat(shmid, nullptr, 0);
// 用它
sleep(5);
// 去关联
shmdt(str);
return 0;
}
IpcShmSer.cc
#include "Comm.hpp"
#include "Log.hpp"
#include <unistd.h>
using namespace std;
// 我想创建全新的共享内存
const int flags = IPC_CREAT | IPC_EXCL;
// 充当使用共享内存的角色
int main()
{
key_t key = CreateKey();
Log() << "key: " << key << "\n";
Log() << "create share memory begin\n";
int shmid = shmget(key, MEM_SIZE, flags | 0666);
if (shmid < 0)
{
Log() << "shmget: " << strerror(errno) << "\n";
return 2;
}
Log() << "create shm success, shmid: " << shmid << "\n";
sleep(5);
// 1. 将共享内存和自己的进程产生关联attach
char *str = (char *)shmat(shmid, nullptr, 0);
Log() << "attach shm : " << shmid << " success\n";
sleep(5);
// 用它
// 2. 去关联
shmdt(str);
Log() << "detach shm : " << shmid << " success\n";
sleep(5);
// 删它
shmctl(shmid, IPC_RMID, nullptr);
Log() << "delete shm : " << shmid << " success\n";
sleep(5);
return 0;
}