(4)linux进程通讯之共享内存
来源:互联网 发布:sql server 字段赋值 编辑:程序博客网 时间:2024/05/21 16:53
共享内存
①为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程将其映射到自己的私有地址空间,这块就是共享内存区域
②由于可以多个进程共享一段内存,因此也需要依靠某种同步机制(如互斥锁和信号量等)
③共享内存是一种最为高效的进程间通信方式,因为进程可以直接读写内存,而不需要任何数据的拷贝
Shell的ipcs命令可以查看共享内存情况
主要步骤
①创建/打开共享内存
②映射共享内存(即把指定的共享内存映射到进程的地址空间用于访问)
③撤销共享内存映射
④删除共享内存对象
1、创建/打开共享内存
int shmget(key_t key, int size, int shmflg);
参数
key:IPC_PRIVATE 或 一个key_t值(如(key_t)0001),一般使用ftok()
size:共享内存区大小
shmflg:同open函数的权限位,也可以用8进制表示法
返回值
成功:共享内存段标识符
出错:-1
注意
①key是系统建立IPC通讯(消息队列、信号量和共享内存)时必须指定一个ID值。因为一定要唯一!!(要不然IPC通讯就乱套了),我们就想起来了文件或目录的节点号(因为他们是唯一的),那么这个节点号具体怎么用呢,这时候ftok()就出场了。ftok()是将文件的索引节点号取出,前面加上子序号得到key_t的返回值,完全符合我们对键值获取!
②如果key的值指定为IPC_PRIVATE,表明由系统为进程创建一个新的共享内存对象
③shmflg如包含IPC_CREAT,表明如果指定的共享内存不存在,则新建一个对象
ftok()原型如下:
key_t ftok( char * fname, int id )
fname就时你指定的文件名,该文件必须是存在而且可以访问的,若该文件不存在返回0xffffffff
id是子序号,虽然为int,但是只有8个比特被使用(0-255)。
当成功执行的时候,一个key_t键值将会被返回
shmget例子:
int shmid;key_t key;key= ftok("./tmp.txt",0);shmid = shmget(key,1024,0666|IPC_CREAT);
将目录下tmp.txt的索引节点号作为键值,打开共享内存,大小为1024,权限0666,如果共享内存不存在,就创建。
2、映射共享内存
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数
shmid:要映射的共享内存区标识符(shmget()返回值)
shmaddr:将共享内存映射到指定地址(若为NULL,则表示由系统自动完成映射)
shmflg :SHM_RDONLY:共享内存只读,默认0:共享内存可读写
返回值
成功:映射后共享内存的地址
出错:-1
//创立一个共享内存结构体struct share_mm{ int w; char buf[BUFFER_SIZE];}* shmaddr;//映射,并获得映射地址,shmid为创建/打开共享内存的标识符shmaddr=shmat(shmid,0,0);if(shmaddr==(void *)-1){ printf("shmat error\n"); exit(1);}//shmaddr是共享内存的地址,可以对此地址进行读写
3、撤销共享内存映射
int shmdt(const void *shmaddr);
参数
shmaddr:共享内存映射后的地址
返回值
成功:0
出错:-1
例子
if((shmdt(shmaddr))<0) { printf("shmdt error\n"); exit(1); }
4、删除共享内存对象
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数
shmid:要操作的共享内存标识符
cmd : IPC_STAT (获取对象属性)
IPC_SET (设置对象属性)
IPC_RMID (删除对象)
buf : 指定IPC_STAT/IPC_SET时用以保存/设置属性
返回值
成功:0
出错:-1
例子
if((shmctl(shmid,IPC_RMID,NULL))<0)//删除内核中的共享内存 { printf("shmctl error\n"); exit(1); }
最后一个例子
struct share_mm//共享内存结构体{ int pid_r; int pid_w; char buf[BUFFER_SIZE];}*shmaddr;
共享结构体中,pid_r和pid_w保存读写进程的进程号,然后共享内存的read和write通过信号实现同步。
即writer进程通过发送信号告诉reader进程共享内存我已写入新的数据,你可以读;读完后,reader进程通过发送信号告诉writer进程共享内存我已读走新的数据,你可以写;
read.c
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<signal.h>#include<sys/types.h>#include<sys/ipc.h>#include<sys/shm.h>#define BUFFER_SIZE 1024struct share_mm//共享内存结构体{ int pid_r; int pid_w; char buf[BUFFER_SIZE];}*shmaddr;void read_message(int signum){ printf("From father message:%s\n",shmaddr->buf);}int main(){ int shmid; pid_t pid; key_t key; //struct share_mm * shmaddr;//保存映射地址 //创建共享内存 key= ftok("./",0); shmid = shmget(key,sizeof(struct share_mm),0666|IPC_CREAT); if(shmid==-1) { printf("shmget error\n"); exit(1); } else { printf("Shmid is %d\n",shmid); system("ipcs -m"); } //映射,并获得映射地址 shmaddr=shmat(shmid,0,0); if(shmaddr==(void *)-1) { printf("shmat error\n"); exit(1); } else { printf("Chile attach shm is %p\n",shmaddr); system("ipcs -m"); } //初始化共享内存 shmaddr->pid_r=getpid(); shmaddr->pid_w=0; memset((void *)shmaddr->buf,0,BUFFER_SIZE); while(shmaddr->pid_w==0);//等待写进程准备就绪 signal(SIGUSR1,read_message); do { pause();//等带write进程的SIGUSR1信号,到来就读 kill(shmaddr->pid_w,SIGUSR2); }while(strncmp(shmaddr->buf,"quit",4)); printf("Writer byebye\n"); if((shmdt(shmaddr))<0) { printf("shmdt error\n"); exit(1); } exit(0); return 0;}
write.c
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<sys/types.h>#include<sys/ipc.h>#include<sys/shm.h>#include<signal.h>#define BUFFER_SIZE 1024struct share_mm//共享内存结构体{ int pid_r; int pid_w; char buf[BUFFER_SIZE];}* shmaddr;void write_message(int signum){ memset((void *)shmaddr->buf,0,BUFFER_SIZE); printf("In father process:\nPlease write message\n"); gets(shmaddr->buf);//从键盘写入数据到共享内存}int main(){ int shmid; pid_t pid; key_t key; //struct share_mm * shmaddr;//保存映射地址 //创建共享内存 key= ftok("./",0); shmid = shmget(key,sizeof(struct share_mm),0666); if(shmid==-1) { printf("shmget error\n"); exit(1); } else { printf("Shmid is %d\n",shmid); system("ipcs -m"); } //映射,并获得映射地址 shmaddr=shmat(shmid,0,0); if(shmaddr==(void *)-1) { printf("shmat error\n"); exit(1); } else { printf("Chile attach shm is %p\n",shmaddr); system("ipcs -m"); } //初始化共享内存 shmaddr->pid_w=getpid(); signal(SIGUSR2,write_message); printf("In father process:\nPlease write message\n"); gets(shmaddr->buf);//从键盘写入数据到共享内存 do { kill(shmaddr->pid_r,SIGUSR1); pause(); }while(strncmp(shmaddr->buf,"quit",4)); kill(shmaddr->pid_r,SIGUSR1);//通知reader进程推出 waitpid(shmaddr->pid_r,NULL,0);//等待读进程先退出 printf("Reader byebye\n"); if((shmdt(shmaddr))<0) { printf("shmdt error\n"); exit(1); } if((shmctl(shmid,IPC_RMID,NULL))<0)//删除内核中的共享内存 { printf("shmctl error\n"); exit(1); } exit(0); return 0;}
linux进程通讯的总结:
pipe: 具有亲缘关系的进程间,半双工,数据在内存中
fifo: 可用于任意进程间,双工,有文件名,数据在内存
signal: 唯一的异步通信方式
shm:效率最高(直接访问内存) ,需要同步、互斥机制
- (4)linux进程通讯之共享内存
- Linux进程间通讯之共享内存
- Linux进程间通讯之共享内存
- linux进程通讯-共享内存
- linux进程通讯-共享内存
- linux进程通讯-共享内存
- Linux 进程间通讯之共享内存方式
- Linux 进程间通讯之共享内存方式
- 进程通讯(共享内存)
- Linux进程通讯:管道通讯、信号通讯、共享内存
- Linux 进程间通讯(IPC)方式 ------- 共享内存
- linux-进程间通讯(信号量,共享内存)
- linux 进程间通讯-共享内存
- Linux进程通讯之一:共享内存
- Unix/linux 进程间通讯 - 共享内存
- Linux进程间共享内存通讯
- linux进程间通讯-共享内存
- Linux进程间通讯五--共享内存
- Java基础,创建线程的两种方法
- 数据库备份和恢复以及表数据的导入和导出
- SparkR终极解决方案
- 字符串转换成整数-微软面试题
- Django项目配置让其他用户电脑访问Project
- (4)linux进程通讯之共享内存
- 先序遍历
- 练习24
- 解决 This application requires Java Runtime Environment X
- CentOS6.5final下TFS的安装和使用
- Linux系统的下载和安装
- hadoop序列化和反序列化
- 生产者和消费者
- ansible命令