linux 之 system-v 共享内存
发布日期:2021-05-01 02:21:35
浏览次数:68
分类:技术文章
本文共 3922 字,大约阅读时间需要 13 分钟。
主要作用
- 不同进程之间,高效率传输大量的数据。
- 高效率是相对于之前谈及的
管道
和消息队列
而言(我的另外几篇博文中有)的。管道和消息队列
需要借助linux kernel
来进行数据转交,效率较低,适合传输少量数据。 - 把
进程1对应的虚拟地址
和进程2对应的虚拟地址
映射到同样的物理空间。那么进程1往它的虚拟地址写,进程2读它自己的虚拟地址就能直接读到。
共享内存的用法
- 定义一个唯一的
key
(可以用ftok() 也可以认为指定键值 (key_t 0x666 )) - 构造一个
共享内存对象
(shmget) - 共享内存映射(shmat)
- 解除共享内存映射(shmdt)
- 删除共享内存(shmctl RMID)
shmget函数
- 功能:获取共享内存对象的id
- 函数原型:
int shmget(key_t key,int size,int shmflg);
-
参数:
-
key:共享内存键值(可以自己定义,也可以依靠ftok函数)
-
size:共享内存大小
-
shmflg:
- IPC_CREAT:共享内存不存在则创建
- mode:共享内存 rwx 权限
-
-
返回值:
- 成功:共享内存id
- 失败:-1
shmat函数
- 功能:映射共享内存
- 函数原型:
void* shmat(int shmid,const void *shmaddr,int shmflg);
-
参数:
- shmid:共享内存id
- shmaddr:映射地址,为NULL时表示自动分配
- shmflg: SHM_RDONLY:只读方式映射 0:可读可写
-
返回值:
- 成功:共享内存地址
- 失败:-1
shmdt函数
- 功能:解除共享内存映射
- 函数原型:
int shmdt(const void *shmaddr);
-
参数:
- shmaddr:映射地址
-
参数:
- 成功:0
- 失败:-1
shmctl函数
- 功能:获取或设置共享内存的相关属性
- 函数原型:
int shmctl(int shmid,int cmd,struct shmid_ds *buf);
-
参数:
-
shmid:共享内存id
-
cmd:
IPC_STAT:获取共享内存的属性信息,由参数buf返回
IPC_SET:设置共享内存的属性,由参数buf传入 IPC_RMID:删除共享内存 -
buf:属性缓冲区
-
-
返回值:
- 成功:由cmd类型决定,上面列出的这三个都返回-1.
- 失败:-1
测试代码
#include#include #include #include #include #include #include #include #include #include #include union semun{ int val; struct semid_ds *buf;};//初始化信号量int init_sem(int sem_id,int init_value){ union semun sem_union; sem_union.val = init_value; if(semctl(sem_id,0,SETVAL,sem_union) == -1) { printf("Initialize semaphore.\n"); return -1; } return 0;}//删除信号量int del_sem(int sem_id){ union semun sem_union; if(semctl(sem_id,0,IPC_RMID,sem_union) == -1) { perror("Delete semahore.\n"); return -1; }}// p 操作int sem_p(int sem_id){ pid_t a; struct sembuf sops; printf("%s(%d):pid = %d\n", __FILE__, __LINE__, getpid()); sops.sem_num = 0;//单个信号量的编号应该为0 sops.sem_op = -1;//表示 p 操作,减操作 sops.sem_flg = SEM_UNDO;//到最后系统会自动释放系统中残留的信号量 printf("%s(%d):pid = %d\n", __FILE__, __LINE__, getpid()); if(semop(sem_id,&sops,1) == -1)//不符合操作条件时会阻塞于此 { perror("P operation.\n"); return -1; } printf("%s(%d):pid = %d\n", __FILE__, __LINE__, getpid()); return 0;}// v 操作int sem_v(int sem_id){ pid_t a; struct sembuf sops; printf("%s(%d):pid = %d\n", __FILE__, __LINE__, getpid()); sops.sem_num = 0;//单个信号量的编号为 0 sops.sem_op = 1;//表示 v 操作 sops.sem_flg = SEM_UNDO;//系统自动释放残留的信号量 printf("%s(%d):pid = %d\n", __FILE__, __LINE__, getpid()); if(semop(sem_id,&sops,1) == -1)//不符合操作条件时会阻塞于此 { perror("V operation.\n"); return -1; } printf("%s(%d):pid = %d\n", __FILE__, __LINE__, getpid()); return 0;}#define DELAY_TIME 3int main(void){ pid_t result; int sem_id; int shm_id; char *addr; //创建一个信号量 sem_id = semget((key_t)6666, 1, 0666 | IPC_CREAT); //创建一个共享内存对象 shm_id = shmget((key_t)7777, 1024, 0666 | IPC_CREAT); //信号量的id,和信号量初始化的值为0 init_sem(sem_id, 0); //调用 fork() 函数 result = fork(); if(-1 == result) { perror("Fail fork.\n"); } else if(0 == result)//子进程 { printf("Child process will wait for some seconds ...\n"); sleep(DELAY_TIME); //映射共享内存 addr = shmat(shm_id,NULL,0); if(addr == (void *)-1) { printf("Fail shmat.\n"); exit(-1); } //设置共享内存中的内容 memcpy(addr,"HelloWorld",11); printf("The child process is running ...\n"); //给信号量的值加 1 sem_v(sem_id); } else//父进程 { //同步工作: //若信号量的值已经为0,那么这个减1的操作将阻塞于此 //从而保证子进程运行在父进程的前面 sem_p(sem_id); printf("The father process is running ...\n"); //映射共享内存的地址 addr = shmat(shm_id,NULL,0); if(addr == (void *)-1) { printf("Fail father shmat.\n"); exit(-1); } printf("Shared memory string : %s\n",addr); //解除共享内存映射 shmdt(addr); //删除共享内存映射 shmctl(shm_id,IPC_RMID,NULL); sem_v(sem_id); del_sem(sem_id); } exit(0);}
编译与运行
jl@jl-virtual-machine:~/test$ ./a.out test.c(48):pid = 19588test.c(52):pid = 19588Child process will wait for some seconds ...The child process is running ...test.c(67):pid = 19589test.c(71):pid = 19589test.c(77):pid = 19589test.c(58):pid = 19588The father process is running ...Shared memory string : HelloWorldtest.c(67):pid = 19588test.c(71):pid = 19588test.c(77):pid = 19588jl@jl-virtual-machine:~/test$
测试成功!
- 补充
转载地址:https://blog.csdn.net/engineer0/article/details/109501632 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
网站不错 人气很旺了 加油
[***.192.178.218]2024年04月18日 19时15分00秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
tf input layer
2019-04-30
tf model create
2019-04-30
tf dense layer两种创建方式的对比和numpy实现
2019-04-30
tf initializer
2019-04-30
tf 从RNN到BERT
2019-04-30
tf keras SimpleRNN源码解析
2019-04-30
tf keras Dense源码解析
2019-04-30
tf rnn输入输出的维度和权重的维度
2019-04-30
检验是否服从同一分布
2019-04-30
tf callbacks
2019-04-30
keras、tf、numpy实现logloss对比
2019-04-30
Ubuntu20.04安装微信
2019-04-30
Restful风格的使用
2019-04-30
Swagger基础入门整合SpringBoot
2019-04-30
MyBatisPlus简单入门(SpringBoot)
2019-04-30
攻防世界web进阶区NewsCenter详解
2019-04-30
攻防世界web进阶PHP2详解
2019-04-30
如何解决词达人问题(新)
2019-04-30
攻防世界web进阶区surpersqli详解
2019-04-30
攻防世界web进阶区easytornado详解
2019-04-30