IPC之共享内存(shmget函数、shmat函数、shmdt函数)及其代码示例——linux系统编程
文章目录共享内存介绍shmget:创建共享内存shmat:将创建好的共享内存连接到某个进程,并指定内存空间shmdt:脱钩函数,把共享内存与当前进程脱离开代码实例共享内存介绍共享内存是IPC中效率最高的一个,它是原理是linux内核在内存中开辟一个空间,给进程进行读写。每个进程都会通过API函数,把这块linux内核中的内存映射到自己的进程空间里面来,是映射的,虚拟的,不是实际在进程内存中。通过这
共享内存介绍
共享内存是IPC中效率最高的一个,它是原理是linux内核在内存中开辟一个空间,给进程进行读写。
每个进程都会通过API函数,把这块linux内核中的内存映射到自己的进程空间里面来,是映射的,虚拟的,不是实际在进程内存中。
通过这种方法来达到进程间共享数据目的
• 共享内存使用的函数与信号量的很相似,涉及到的函数如下
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmget(key_t key, int size, int shmflg);
int shmdt(const void *shmaddr);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmget:创建共享内存
int shmget(key_t key,size_t size, int shmflg);
• key: 这个共享内存段的名字,我们通常自定义数字并用key_t类型强转
• size: 需要共享的内存量
• shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
• 如果共享内存创建成功,shmget将返回一个非负整数,即该段共享内存的标识码;如果失败,则返回“-1”
例子:
int shm_id;
shm_id = shmget((key_t)6677, SHM_ZIZE_MAX, IPC_CREAT | 0666);//666可读可写
shmat:将创建好的共享内存连接到某个进程,并指定内存空间
void *shmat(int shmid, const void *shmaddr, int shmflg);
• shm_id: shmget返回的共享内存标识
• shm_addr:把共享内存连接到当前进程去的时候准备放置它的那个地址
• shmflg是一组按位OR(或)在一起的标志。它的两个可能取值是SHM_RND和SHM_RDONLY
• 调用成功,返回一个指针,指针指向共享内存的第一个字节,如果失败,则返回“-1”
void *shm_addr = NULL;
//shmat的第二个参数shm_addr:把共享内存连接到当前进程去的时候准备放置它的那个地址,为NULL为让系统自动选择
//第三个参数是一组按位OR(或)在一起的标志,SHM_RDONLY表示只读
shm_addr = shmat(shm_id, NULL, SHM_RDONLY);
• shmaddr为0(NULL),核心自动选择一个地址
• shmaddr不为0且shmflg无SHM_RND标记,则以shmaddr为连接地址。
• shmaddr不为0且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr - (shmaddr % SHMLBA)
• shmflg=SHM_RDONLY,表示连接操作用来只读共享内存
注意点:
• 在fork() 后,子进程继承已连接的共享内存
• 在exec后,已连接的共享内存会自动脱离(detach)
• 在结束进程后,已连接的共享内存会自动脱离(detach)
shmdt:脱钩函数,把共享内存与当前进程脱离开
int shmdt(const void *shmaddr);
• shm_addr: 由shmat返回的地址指针
• 操作成功,返回“0”,失败则返回“-1”
• 脱离共享内存并不等于删除它,只是当前进程不能再继续访问它而已
注意:共享内存实际是独立于内存存在的,意味着进程结束后,共享内存以及里面保存的数据实际还存在。
代码实例
共享内存写入端:
#include <iostream>
#include<unistd.h>//unix stand lib
#include<sys/types.h>
#include<sys/fcntl.h>
#include<sys/stat.h>
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include<dirent.h>//file dir
#include <sys/wait.h>//wait func
#include <stdlib.h>//ststem
#include <signal.h>
#include <string.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/shm.h>
using namespace std;
typedef struct
{
int age;
char name[10];
}STU;
#define SHM_ZIZE_MAX 4096
int main(int argc, char *argv[])
{
int shm_id;
shm_id = shmget((key_t)6677, SHM_ZIZE_MAX, IPC_CREAT | 0666);//666可读可写
if (shm_id == -1)
{
perror("shm create error");
return -1;
}
STU stu_info = { 19, "rabbit" };
void *shm_addr = NULL;
//shmat的第二个参数shm_addr:把共享内存连接到当前进程去的时候准备放置它的那个地址,为NULL为让系统自动选择
//第三个参数是一组按位OR(或)在一起的标志,0表示可读可写
shm_addr = shmat(shm_id, NULL, 0);
//要对内存清空一下
memset(shm_addr, 0, SHM_ZIZE_MAX);
//写进内存:memcpy因为映射就看做是自己的内存
memcpy(shm_addr, &stu_info, sizeof(STU));//地址,内容,大小
cout << "memcpy(shm_addr, &stu_info, sizeof(STU))" << endl;
while(1){sleep(1);}
shmdt(shm_addr);//脱钩函数
return 0;
共享内存读出端:
#include <iostream>
#include<unistd.h>//unix stand lib
#include<sys/types.h>
#include<sys/fcntl.h>
#include<sys/stat.h>
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include<dirent.h>//file dir
#include <sys/wait.h>//wait func
#include <stdlib.h>//ststem
#include <signal.h>
#include <string.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/shm.h>
typedef struct
{
int age;
char name[10];
}STU;
#define SHM_ZIZE_MAX 4096
int main(int argc, char *argv[])
{
int shm_id;
shm_id = shmget((key_t)6677, SHM_ZIZE_MAX, IPC_CREAT | 0666);//666可读可写
if (shm_id == -1)
{
perror("shm create error");
return -1;
}
STU stu_info;
STU *recv_stu_info;
bzero(&stu_info, sizeof(STU));
void *shm_addr = NULL;
//shmat的第二个参数shm_addr:把共享内存连接到当前进程去的时候准备放置它的那个地址,为NULL为让系统自动选择
//第三个参数是一组按位OR(或)在一起的标志,SHM_RDONLY表示只读
shm_addr = shmat(shm_id, NULL, SHM_RDONLY);
//法一:从内存中拿出来:memcpy因为映射就看做是自己的内存
//memcpy(&stu_info, shm_addr,sizeof(STU));//地址,内容,大小
//cout << "stu_info.name" << stu_info.name << endl;
//法二:也可以直接把共享内存指针强制转换成STU*,这时要shmat的参数3改为0读写
//这里也说明如果有进程把数据写入共享内存,如果没有其他进程去修改或清除
//那么数据永远都在里面,消息队列和共享内存里面的数据生命周期和进程不同(进程消失了数据可以还在)
recv_stu_info = (STU*)shm_addr;
cout << "stu_info.name" << recv_stu_info->name << endl;
shmdt(shm_addr);//脱钩函数
return 0;
}
更多推荐
所有评论(0)