进程间通信之共享内存
来源:互联网 发布:小米机顶盒下载软件 编辑:程序博客网 时间:2024/06/06 04:18
概述
共享内存就是分配一块能被其他进程访问的内存。
共享内存的数据结构
共享内存和消息队列,信号量一样,在内核中也维护着一个内部结构。
#include<linux/shm.h>{ struct ipc_perm shm_perm; int shm_segsz; __kernel_time_t shm_atime; __kernel_time_t shm_dtime; __kernel_time_t shm_ctime; __kernel_ipc_pid_t shm_cpid; __kernel_ipc_pid_t shm_lpid; unsigned short shm_nattch; unsigned short shm_unused; void *shm_unused2; void *shm_unused3; }
代码中主要字段含义如下:
- shm_perm:操作许可,包含共享内存的用户ID,组ID
- shm_segsz:共享内存段的大小,单位是字节
- shm_atime:最后一个进程访问共享内存的时间
- shm_dtime:最后一个进程离开共享内存的时间
- shm_ctime:最后一次修改共享内存的时间
- shm_cpid:创建共享内存的进程ID
- shm_lpid:最后操作共享内存的进程ID
- shm_nattch:当前使用该共享内存的进程数量
共享内存的创建与操作
共享内存区的创建
#include<linux/shm.h>int shmget(key_t key, size_t size, int shmflg)
各个参数说明如下:
- key:由ftok函数得到的键值
- size:指定内存的大小,以字节为单位
- shmflg:操作标志位
shmflg的宏取值:
- IPC_CREATE:调用shmget时,系统将此值与其他所有共享区内的key进行比较,key值相同的,返回已存在的内存共享区标识符,否则新建一个内存共享区并返回其标识符
- IPC_EXCL:单独使用无意义,与上述参数结合使用,不同的是如果共享内存中已有和现在的key值相等的,直接返回-1,错误码为EEXIST
注意:如果创建一个新的内存共享区,必须使size大于0,否则置size为0。
共享内存区的操作
在使用共享内存之前,必须先使用shmat函数将共享内存附加到进程的地址空间中,这样共享内存就和进程建立了联系。
#include<linux/shm.h>void *shmat(int shmid, const void *shmaddr, int shmflg)
该函数调用成功会返回一个指向共享内存区的指针,使用该指针就可以访问共享内存区了,函数调用失败返回-1。
各参数说明如下:
- shmid:函数shmget的返回值
- shmflg:存取权限标志
- shmaddr:共享内存的附加点
参数shmaddr取值:
- NULL:由内核选择一个空闲的内存区
- !=NULL:返回地址取决于调用者是否给shmflg参数指定了SHM_RND值,如果没有指定,则共享内存区附加到由shmaddr指定的地址,否则附加地址为shmaddr 向下舍入一个共享内存低端边界地址后的地址
注意:通常将参数shmaddr设置为NULL。
当进程结束使用共享内存区时,要通过函数shmdt断开与共享内存区的连接。
#include<sys/shm.h>int shmdt(const void *shmaddr)
参数shmaddr为shmat函数的返回值。函数调用成功后,返回0,否则返回-1。进程脱离共享内存区后,数据结构shmid_ds中的shm_nattch就会减一。此时共享内存段仍然存在,只有当shm_nattch为0的时候,共享内存区才会被删除。一般来说,当一个进程终止的时候,它所附加的共享内存区都会自动脱离。
共享内存区的控制
#include<sys/shm.h>int shmctl(int shmid, int cmd, struct shmid_ds *buf)
各参数说明如下:
- shmid:共享内存区的标识符
- buf:指向shmid_ds结构体的指针
- cmd:操作的标志位
cmd 3种控制操作:
- IPC_RMID:从系统中删除由shmid标识的共享内存区
- IPC_SET:设置共享内存区的shmid_ds结构
- IPC_STAT:读取共享内存区的shmid_ds结构,并将其存储到buf所指向的地址当中
共享内存的应用实例
本例通过共享内存和信号量的配合使用,使一个进程读共享内存的时候,其他进程不能写内存;当一个进程写共享内存的时候,其他进程不能读内存。
sharemem.h:(将函数接口写好)
#ifndef _SHAREMEM_H#define _SHAREMEM_H#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/types.h>#include<sys/ipc.h>#include<sys/sem.h>#include<sys/shm.h>#include<errno.h>#define SHM_SIZE 1024 //共享内存的大小union semun //信号集的结构体{ int val; struct semid_ds *buf; unsigned short *array;};/*创建信号量函数*/int createsem(const char *pathname, int proj_id, int members, int init_val){ key_t msgkey; int index,sid; union semun semopts; if((msgkey = ftok(pathname, proj_id)) == -1) //创建键值 { perror("ftok error"); exit(1); } if((sid = semget(msgkey, members, IPC_CREAT | 0666)) == -1) //创建信号集 { perror("semget error"); exit(1); } /*初始化操作*/ semopts.val = init_val; for(index = 0; index < members; index++) { semctl(sid, index, SETVAL, semopts); } return sid; //返回信号集标志符}/*打开信号量函数*/int opensem(const char *pathname, int proj_id){ key_t msgkey; int sid; if((msgkey = ftok(pathname, proj_id)) == -1) { perror("ftok error"); return -1; } if((sid = semget(msgkey, 0, IPC_CREAT | 0666)) == -1) { perror("semget call failed"); return -1; } return sid;}/*P操作函数*/int sem_P(int semid, int index){ struct sembuf buf = {0, -1, IPC_NOWAIT}; if(index < 0) { perror("No index"); return -1; } buf.sem_num = index; if(semop(semid, &buf, 1) == -1) //第三个参数表示要操作信号的个数 { perror("semop error"); return -1; } return 0;}/*V操作函数*/int sem_V(int semid, int index){ struct sembuf buf = {0, 1, IPC_NOWAIT}; if(index < 0) { perror("No index"); return -1; } buf.sem_num = index; if(semop(semid, &buf, 1) == -1) //第三个参数表示要操作信号的个数 { perror("semop error"); return -1; } return 0;}/*删除信号集函数*/int sem_delete(int semid){ return (semctl(semid, 0, IPC_RMID));}/*等待信号为1*/int wait_sem(int semid, int index){ while(semctl(semid, index, GETVAL) == 0) { sleep(1); } return 1;}/*常见内存共享函数*/int createshm(char *pathname, int proj_id, size_t size){ key_t shmkey; int sid; if((shmkey = ftok(pathname, proj_id)) == -1) //获取键值 { perror("ftok error"); return -1; } if((sid = shmget(shmkey, size, IPC_CREAT | 0666)) == -1) { perror("shmget error"); return -1; } return sid; //返回共享内存标识符}#endif
writer.c:(给共享内存写东西的进程)
#include<stdio.h>#include<string.h>#include<sharemem.h>int main(){ int semid,shmid; char *shmaddr; char write_str[SHM_SIZE]; if((shmid = createshm(".", 'm', SHM_SIZE)) == -1) //创建共享内存区 { exit(1); } if((shmaddr = shmat(shmid, NULL, 0)) == NULL) //得到指向共享内存的指针 { perror("shmat error"); exit(1); } if((semid = createsem(".", 's', 1, 1)) == -1) //创建信号集 { exit(1); } while(1) { wait_sem(semid, 0); //等待信号集中的信号值是否为1 sem_P(semid, 0); //P操作 printf("writer: "); fgets(write_str, 1024, stdin); int len = strlen(write_str) -1; write_str[len] = '\0'; //将'\n'去掉 strcpy(shmaddr, write_str); sleep(3); //使reader,读进程处于阻塞状态 sem_V(semid, 0); //V操作 sleep(5); //等待reader进行读操作 } return 0;}
reader.c:(从共享内存读东西的进程)
#include<stdio.h>#include"sharemem.h"int main(){ int semid, shmid; char *shmaddr; if((shmid = createshm(".", 'm', SHM_SIZE)) == -1) { exit(1); } if((shmaddr = shmat(shmid, NULL, 0)) == NULL) { perror("shmat error"); exit(1); } if((semid = opensem(".", 's')) == -1) { exit(1); } while(1) { printf("reader:"); wait_sem(semid, 0); sem_P(semid, 0); printf("%s\n", shmaddr); sleep(3); sem_V(semid, 0); sleep(5); } return 0;}
运行结果:
写端:
读端:
内存共享实现了进程间通信,并且信号量可以实现锁的功能。
- linux进程间通信之共享内存
- 进程间通信之共享内存篇
- linux进程间通信之共享内存
- 进程间通信之共享内存
- 进程间通信之共享内存
- 进程间通信之共享内存
- 进程间通信之共享内存篇
- 进程间通信之共享内存
- Linux进程间通信之共享内存
- Linux进程间通信之共享内存
- 进程间通信之共享内存
- Windows进程间通信之共享内存
- 进程间通信之共享内存
- 进程间通信之共享内存
- QT 进程间通信 之 共享内存
- 进程间通信IPC之--共享内存
- 进程间通信之共享内存
- linux进程间通信之共享内存
- 关于初次使用IEDA 2016.2.4 新建javaSE工程的问题
- 多个acitivity之间层层传递数据的处理
- 排序算法--总结
- 内存四驱模型
- Java知识点杂烩
- 进程间通信之共享内存
- 【Java基础】内部类复习
- Windows基于MySQL5.7.15重置密码
- 中国剩余定理:D - Biorhythms
- HihoCoder上网络流算法题目建模总结
- 微信公众平台开发
- C++ virtual函数 实现机制——虚函数地址在虚表中的分布
- POJ 3275 两种做法
- Android6.0请求权限