System V共享内存
System V 标准的进程间通信方式是在OS层面专门为进程间通信设计的一个方案,通过系统调用的方式给用户提供功能。在同一个主机内的进程间通信方案叫作system V方案。
共享内存区是最快的IPC形式,一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说进程不再通过执行进入内核的系统调用来传递彼此的数据。
共享内存函数接口
shmget
功能:用来创建共享内存
int shmget(key_t key, size_t size, int shmflg);
参数:
key:这么共享内存段名字
size:共享内存大小
shmflg:由九个权限标志构成
返回值:成功返回一个非负整数,即该共享内存段的标识码,失败返回-1
shmat
功能:将共享内存段连接到进程地址空间
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数
shmid:共享内存标识
shmaddr:指定连接的地址
shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一个指针,指向共享内存第一个字节,失败返回-1
说明:
shmaddr为NULL,核心自动选择一个地址
shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址
shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址向下调整为SHMLBA的整数倍,公式:shmaddr - (shmaddr % SHMLBA)
shmflg = SHM_RDONLY,表示连接操作用来读共享内存
shmdt
功能:将共享内存段与当前进程脱离
int shmdt(const void *shmaddr);
参数:
shmaddr:由shmaddr:由shmat所返回的指针
返回值:成功返回0,失败返回-1
shmctl
功能:用于控制共享内存
int shmctl (int shmid, int cmd, struct shmid_ds * buf);
shmid:由shmget返回的共享内存标识码
cmd:将要采取的动作
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0,失败返回-1
示例
在这个实例中我们希望在客户端(client)写入数据,服务端读取数据。共享内存只需在服务端申请一次即可,但在客户端和服务端中都要与共享内存连接。
server.c
#include "comm.h" "
#include <unistd.h>
int main()
{
// 提供一个文件地址和Id,以得到一个唯一标识值
// 并非随机值,只要地址和Id相同,就会得到相同的值
// 因此在server和client中要保证文件地址和Id相同
// 以得到同一个id
key_t key = ftok(PATH_NAME, PRO_ID);
if (key < 0)
{
perror("ftok");
return 1;
}
printf("%u\n", key);
int shmid = shmget(key, SIZE, IPC_CREAT | IPC_EXCL | 0666);
// 如没有则创建,有则返回已有的
// 如没有则创建,有则报错
if (shmid < 0)
{
perror("shmget");
return 2;
}
printf("shmid : %u\n", shmid);
//sleep(10);
char *mem = (char*)shmat(shmid, NULL, 0);
while (1)
{
printf("%s\n", mem);
sleep(1);
}
shmdt(mem);
// 并非释放了此共享内存,只是解除共享内存与该进程的关联
printf("attach success\n");
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
client.c
#include "comm.h"
int main()
{
key_t key = ftok(PATH_NAME, PRO_ID);
if (key < 0)
{
perror("ftok");
return 1;
}
printf("%u\n", key);
int shmid = shmget(key, SIZE, IPC_CREAT);
if (shmid < 0)
{
perror("shmget");
return 2;
}
char *mem = (char*)shmat(shmid, NULL, 0);
printf("client attach success\n");
//sleep(5);
char ch = 'A';
while (ch <= 'Z')
{
mem[ch - 'A'] = ch;
ch++;
mem[ch - 'A'] = 0;
sleep(2);
}
shmdt(mem);
printf("client detach success\n");
sleep(5);
return 0;
}
comm.h
#pragma once
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <unistd.h>
#define PATH_NAME "./"
#define PRO_ID 0x666
#define SIZE 4096
总结
在本篇文章中对共享内存的操作主要是这几块
1.创建共享内存
流程:获取一个key值,用这个key值来获得id
2.关联共享内存
通过shmat函数
3.去关联共享内存
通过shmdt函数
4.释放共享内存
通过shmctl函数