本期我将要带大家学习的是有关进程间通信的另一种方式——共享内存。共享内存是一种用于进程间通信的高效机制,允许多个进程访问和操作同一块内存区域。
目录
【解释说明】?
【解释说明】
struct shmid_ds {
struct ipc_perm shm_perm; /* operation perms */
int shm_segsz; /* size of segment (bytes) */
__kernel_time_t shm_atime; /* last attach time */
__kernel_time_t shm_dtime; /* last detach time */
__kernel_time_t shm_ctime; /* last change time */
__kernel_ipc_pid_t shm_cpid; /* pid of creator */
__kernel_ipc_pid_t shm_lpid; /* pid of last operator */
unsigned short shm_nattch; /* no. of current attaches */
unsigned short shm_unused; /* compatibility */
void *shm_unused2; /* ditto - used by DIPC */
void *shm_unused3; /* unused */
};
在Linux系统中,共享内存通常通过系统调用来实现。以下是一些与共享内存相关的主要函数:
ftok函数:
- 功能:生成一个唯一的key,用于标识共享内存段。
- 参数:
keyfile
:与路径名相关的文件名,可以是一个存在的文件。id
:一个非零整数。- 返回值:生成的key。
?man 手册查询结果:
shmget函数
功能:用来创建共享内存
原型:int shmget(key_t key, size_t size, int shmflg);
参数
- key:这个共享内存段名字
- size:共享内存大小
- shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1
??man 手册查询结果:
shmat函数
功能:将共享内存段连接到进程地址空间
原型:void *shmat(int shmid, const void *shmaddr, int shmflg);
参数
- shmid: 共享内存标识
- shmaddr:指定连接的地址
- shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一个指针,指向共享内存第一个节;失败返回-1
??man 手册查询结果:
说明:
?shmdt函数
功能:将共享内存段与当前进程脱离
原型:int shmdt(const void *shmaddr);
参数
- shmaddr: 由shmat所返回的指针
返回值:成功返回0;失败返回-1
注意:将共享内存段与当前进程脱离不等于删除共享内存段
??man 手册查询结果:?
shmctl函数
功能:用于控制共享内存
原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数
- shmid:由shmget返回的共享内存标识码
- cmd:将要采取的动作(有三个可取值)
- buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0;失败返回-1
???man 手册查询结果:?
接下来,我们就用上述描述的接口简单的实现一下共享内存。?
【client.cc】
#include"common.hpp"
#include<unistd.h>
int main()
{
key_t k = getkey();
cout << "client key: " << toHex(k) << endl;
int shmid = getShm(k, gsize);
cout << "client shmid: " <<shmid<< endl;
//3. 将自己和共享内存关联起来
char* start = attachShm(shmid);
sleep(15);
// 4. 将自己和共享内存去关联
detachShm(start);
return 0;
}
【server.cc】
#include"common.hpp"
#include<unistd.h>
int main()
{
//1. 创建key
key_t k = getkey();
cout << "server key: " << toHex(k) << endl;
//2. 创建共享内存
int shmid = createShm(k, gsize);
cout << "server shmid: " << shmid << endl;
sleep(3);
//3. 将自己和共享内存关联起来
char* start = attachShm(shmid);
sleep(15);
// 4. 将自己和共享内存去关联
detachShm(start);
//删除共享内存
delShm(shmid);
return 0;
}
【common.hpp】
#ifndef __COMMON_HPP__
#define __COMMON_HPP__
#include <iostream>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <cassert>
#include <string>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
using namespace std;
#define PATHNAME "."
#define PROJID 0x6666
const int gsize = 4096; //暂时
key_t getkey(){
key_t k =ftok(PATHNAME,PROJID);
if(k == -1)
{
cerr << "error: " << errno << " : " << strerror(errno) << endl;
exit(1);
}
return k;
}
string toHex(int x){
char buffer[64];
snprintf(buffer, sizeof buffer, "0x%x", x);
return buffer;
}
static int createShmHelper(key_t k, int size, int flag){
int shmid = shmget(k, gsize, flag);
if(shmid == -1)
{
cerr << "error: " << errno << " : " << strerror(errno) << endl;
exit(2);
}
return shmid;
}
int createShm(key_t k, int size){
umask(0);
return createShmHelper(k, size, IPC_CREAT | IPC_EXCL | 0666);
}
int getShm(key_t k, int size)
{
return createShmHelper(k, size, IPC_CREAT);
}
void delShm(int shmid){
int n = shmctl(shmid,IPC_RMID,nullptr);
assert(n != -1);
(void)n;
}
char* attachShm(int shmid)
{
char *start = (char*)shmat(shmid, nullptr, 0);
return start;
}
void detachShm(char *start)
{
int n = shmdt(start);
assert(n != -1);
(void)n;
}
#endif
总的来说,共享内存是一种强大的进程间通信机制,适用于需要高效、频繁共享大量数据的场景。在使用时需要注意同步和互斥机制,以确保数据的一致性和安全性。