进击吧,linux(十七) 共享内存通讯
0赞
Linux进程和进程之间有多种通讯方式。Linux进程间通讯的主要方式有:
1、 无名管道
2、 有名管道
3、 信号
4、 消息队列
5、 共享内存
6、 信号量
7、 套接字
共享内存通讯,从这名字一听就知道这个通讯的方式了。就是利用内存进行通信。两个进程对内存的同一个区域进行数据操作,不就能进行通信了。
通过下面一个图就能清楚的知道共享内存通信。
同样,对共享内存学习也是学习几个函数。
10.1.1 函数名
shmget
10.1.2 函数原型
int shmget(key_t key, size_t size, int shmflg)
10.1.3 函数功能
创建或者获取共享内存,并返回其描述符id
10.1.4 所属头文件
<sys/ipc.h> <sys/shm.h>
10.1.5 函数返回值
成功: 共享内存的描述符
失败: -1
10.1.6 参数说明
key: 共享内存的键值
size: 创建的共享内存的大小
shmflg:打开标志
-IPC_CREAT: key所关联的共享内存不存在,就创建共享内存
10.2.1 函数名
shmat
10.2.2 函数原型
void *shmat(int shmid, const void *shmaddr, int shmflg)
10.2.3 函数功能
把指定的shmid共享内存映射到进程的地址空间去
10.2.4 所属头文件
<sys/types.h> <sys/shm.h>
10.2.5 函数返回值
成功: 返回映射到进程空间之后的内存地址
失败: -1
10.2.6 参数说明
shmid: 共享内存的描述符
shmaddr:指定映射后的内存地址,一般设置为空,即NULL,让系统自动选择映射地址
shmflg:标志,一般设置为0
10.3.1 函数名
shmdt
10.3.2 函数原型
int shmdt(const void *shmaddr)
10.3.3 函数功能
从进程地址空间中,断掉与共享内存的联系
10.3.4 所属头文件
<sys/types.h> <sys/shm.h>
10.3.5 函数返回值
成功: 0
失败: -1
10.3.6 参数说明
shmaddr: 要断开的共享内存的映射地址
10.4.1 函数名
shmctl
10.4.2 函数原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
10.4.3 函数功能
控制共享内存
10.4.4 所属头文件
<sys/ipc.h> <sys/shm.h>
10.4.5 函数返回值
成功: 根据不同的操作返回不同的值
失败: -1
10.4.6 参数说明
shmid:共享内存的描述符
cmd: 对共享内存的操作命令
-IPC_STAT: 从指定的共享内存的内核数据中读取数据到buf结构体中
-IPC_SET: 将buf结构体中数据写入到指定的共享内存的内核数据中
-IPC_RMID:删除共享内存
buf: 一个结构体,指向shmid_ds结构体,获取linux中描述共享内存的结构。基本不使用。
其中的struct ipc_perm也是一个结构体
下面就是写代码来学习以上的函数。
有两个进程AB,进程A创建一个共享内存,然后往这个共享内存中写入数据,进程B获取A创建的共享内存,然后从这共享内存中读取数据。当A进程写入weiqi7777,通信结束,两个进程分离共享内存,最后B进程删除共享内存。
A进程:
#include<sys/ipc.h> #include<sys/shm.h> #include<sys/types.h> #include<stdio.h> #include<unistd.h> #include<stdlib.h> #define TEXT_SZ 2048 struct memory_share { int flag; char text[TEXT_SZ]; }; void main() { key_t key; int shmid; struct memory_share *p; char data[TEXT_SZ]; /*创建键值*/ key = ftok("/home",6); /*创建共享内存*/ shmid = shmget(key,sizeof(struct memory_share),IPC_CREAT); if(shmid == -1) { printf("create shm failed\n"); exit(EXIT_FAILURE); } /*映射共享内存*/ p = (struct memory_share *)shmat(shmid,NULL,0); /*往共享内存放入数据*/ while(1) { while(p->flag == 1); fgets(data,TEXT_SZ,stdin); strncpy(p->text,data,TEXT_SZ); p->flag = 1; if(strncmp(data,"weiqi7777",9) == 0 ) break; } /*分离共享内存*/ shmdt((const void *)p); }
A进程首先创建键值,因为共享内存是和键值关联的,然后再通过这个键值创建一个共享共存,并将struct memory_share p结构体与共享内存关联。然后就往结构体p中写入数据,不就相当于往共享内存中写入数据了。
最后判断写入的数据是不是weiqi7777,是的话就退出循环,通信结束,然后分离共享内存。
B进程:
#include<sys/ipc.h> #include<sys/shm.h> #include<sys/types.h> #include<stdio.h> #include<unistd.h> #include<stdlib.h> #define TEXT_SZ 2048 struct memory_share { int flag; char text[TEXT_SZ]; }; void main() { key_t key; int shmid; struct memory_share *p; char data[TEXT_SZ]; /*创建键值*/ key = ftok("/home",6); /*获取共享内存*/ shmid = shmget(key,sizeof(struct memory_share),IPC_CREAT); if(shmid == -1) { printf("create shm failed\n"); exit(EXIT_FAILURE); } /*映射共享内存*/ p = (struct memory_share *)shmat(shmid,NULL,0); /*从共享内存里面读取数据,并打印*/ while(1) { while(p->flag != 1); strncpy(data,p->text,TEXT_SZ); p->flag = 0; printf("read data: %s",data); if(strncmp(data,"weiqi7777",9) == 0 ) break; } /*分离共享内存*/ shmdt((const void *)p); /*删除共享内存*/ shmctl(shmid,IPC_RMID,NULL); }
B进程首先也是创建键值,创建的键值和A进程创建的进程要是一样的,然后再通过这个键值获取与A进程创建的共享共存,并将struct memory_share p结构体与共享内存关联。然后就从结构体p中读取数据,不就相当于从共享内存中读取数据了。
最后判断读取的数据是不是weiqi7777,是的话就退出循环,通信结束,然后分离共享内存,最后删除共享内存。
运行程序:
两个进程运行,A进程在等待输入输入,B进程在等待A进程往共享内存中写入数据。
A进程接收键盘输入数据,写入到共享内存中,B进程从共享内存中读取数据,并显示。
当输入的数据是weiqi7777时,两个进程结束,分离共享内存,B进程删除共享内存。
以上就实现了进程间共享内存通信,其实也是比较简单的。