进程间通讯—共享内存
2017-11-03 12:57
225 查看
一、共享内存,额从名字上来看,就是我能用的你的,你也能用我的呗。
共享内存就是允许两个以上不相关的进程访问同一个逻辑内存。
![](https://img-blog.csdn.net/20171103120259780?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTHl0MTU4Mjk3OTc3NTE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
中间红色部分就是A、B 进程共享的区域
那么多个进程之间是如何完成共享的呢?换句话说,欸,我怎么才能找到这块共享的宝地呢?
![](https://img-blog.csdn.net/20171103120622112?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTHl0MTU4Mjk3OTc3NTE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
共享内存也有内核对象来管理共享区域
上面的图就解释了,如何找到共享内存的。 每个进程都通过内核去创建共享区域,然后共享区域返回给该进程指向共享内存首地址的指针,这样每个进程通过返回的指针就能指向这块共享区域了。
特点:共享内存是最快的一种IPC,开辟内存在各个进程都有指针直接指向开辟内存区域,访问时当做本进程中的一个内存。
二、共享内存的操作函数:
1: int shmget(key_t key,size,int shmflg)
size指需要共享的内存容量
shmflg 权限加标志
成功返回共享内存ID,失败返回-1
2: void * shmat(int shmid,const void *addr,int flag)
第一次创建完共享内存时,它还不能被任何进程访问,shmat的作用就是启动对该共享内存的访问,并把共享内存连接到当前进程的地址空间。
第一个参数是共享内存ID
第二参数:共享内存连接到当前进程中的地址位置,如果置为NULL,表示系统默认选择共享内存的地址。
flag我们一般给0。
成功函数返回指向共享内存第一个字节的指针,失败返回-1。
3: int shmdt(void *addr)
addr就是shmat函数的返回值,也就是指向共享内存地址的指针。
这个函数用于将共享内存从当前进程中分离,断开连接,但并没有删除,这个共享内存对当前进程不再可用。
4: int shmctl(int shmid,int cmd,struct shmid_ds *buf)
删除共享内存段 ,cmd为IPC_RMID。
最后一个参数是内核为每个共享存储段设置了shmid_ds结构。
例子:通过共享内存完成A进程获取用户输入,B进程统计单词个数并输出单词。
这里需要特别注意的是:
共享内存是两个以上的进程能够操作同一块物理空间的内存区域,所以共享的内存就成了临界资源,我们就必须对临界资源的访问做同步控制,那么我们是不是就会用到信号量来加以控制。
这个练习也是同样需要用到信号量来进行同步控制的,因为我们在A进程中完成了写,B进程才能读取并计数,如果我们A进程第一次输完,第二次紧接着输入,B进程就不会读取到第一次输入的。这就与我们所设想的结果大不一样了。
所以说 我们设想的是A进程用户输入一次,B进程读取A进程等待,B进程读完,A进程接着输入,这样循环进行。
那之前不是说同步控制就需要用到信号量吗?那么该如何进程的执行呢?
我们用两个信号量 semid1和semid2,并分别赋初值为0和1。
1、A进程先执行sem_p(semid2),同时B进程执行sem_p(semid1)阻塞其运行,
2、A进程执行完sem_v(semid1),让进程B工作,A这时阻塞等待,
3、B进程执行完sem_v(semid2),A进程再接着执行。
代码如下:
shmwrite.c
shmread.c
共享内存就是允许两个以上不相关的进程访问同一个逻辑内存。
中间红色部分就是A、B 进程共享的区域
那么多个进程之间是如何完成共享的呢?换句话说,欸,我怎么才能找到这块共享的宝地呢?
共享内存也有内核对象来管理共享区域
上面的图就解释了,如何找到共享内存的。 每个进程都通过内核去创建共享区域,然后共享区域返回给该进程指向共享内存首地址的指针,这样每个进程通过返回的指针就能指向这块共享区域了。
特点:共享内存是最快的一种IPC,开辟内存在各个进程都有指针直接指向开辟内存区域,访问时当做本进程中的一个内存。
二、共享内存的操作函数:
1: int shmget(key_t key,size,int shmflg)
size指需要共享的内存容量
shmflg 权限加标志
成功返回共享内存ID,失败返回-1
2: void * shmat(int shmid,const void *addr,int flag)
第一次创建完共享内存时,它还不能被任何进程访问,shmat的作用就是启动对该共享内存的访问,并把共享内存连接到当前进程的地址空间。
第一个参数是共享内存ID
第二参数:共享内存连接到当前进程中的地址位置,如果置为NULL,表示系统默认选择共享内存的地址。
flag我们一般给0。
成功函数返回指向共享内存第一个字节的指针,失败返回-1。
3: int shmdt(void *addr)
addr就是shmat函数的返回值,也就是指向共享内存地址的指针。
这个函数用于将共享内存从当前进程中分离,断开连接,但并没有删除,这个共享内存对当前进程不再可用。
4: int shmctl(int shmid,int cmd,struct shmid_ds *buf)
删除共享内存段 ,cmd为IPC_RMID。
最后一个参数是内核为每个共享存储段设置了shmid_ds结构。
例子:通过共享内存完成A进程获取用户输入,B进程统计单词个数并输出单词。
这里需要特别注意的是:
共享内存是两个以上的进程能够操作同一块物理空间的内存区域,所以共享的内存就成了临界资源,我们就必须对临界资源的访问做同步控制,那么我们是不是就会用到信号量来加以控制。
这个练习也是同样需要用到信号量来进行同步控制的,因为我们在A进程中完成了写,B进程才能读取并计数,如果我们A进程第一次输完,第二次紧接着输入,B进程就不会读取到第一次输入的。这就与我们所设想的结果大不一样了。
所以说 我们设想的是A进程用户输入一次,B进程读取A进程等待,B进程读完,A进程接着输入,这样循环进行。
那之前不是说同步控制就需要用到信号量吗?那么该如何进程的执行呢?
我们用两个信号量 semid1和semid2,并分别赋初值为0和1。
1、A进程先执行sem_p(semid2),同时B进程执行sem_p(semid1)阻塞其运行,
2、A进程执行完sem_v(semid1),让进程B工作,A这时阻塞等待,
3、B进程执行完sem_v(semid2),A进程再接着执行。
代码如下:
shmwrite.c
#include<stdio.h> #include<assert.h> #include<stdlib.h> #include<string.h> #include<sys/ipc.h> #include<sys/shm.h> #include<sys/types.h> #include<unistd.h> #include "sem.h" struct shamem { char buff[1000]; }; int main() { void *shm_memory=(void *)0; struct shamem *p; int semid1=sem_get(1122,0); int semid2=sem_get(2233,1); int shmid=shmget((key_t)1234,1024,0664|IPC_CREAT); assert(shmid!=-1); if(shmid==-1) { perror("error\n"); exit(0); } shm_memory=shmat(shmid,NULL,0); if(shm_memory==(void*)-1) { perror("error"); exit(0); } p=(struct shamem *)shm_memory; while(1) { sem_p(semid2); fgets(p->buff,128,stdin); p->buff[strlen(p->buff)-1]=0; if(strncmp(p->buff,"end",3)==0) { break; } sem_v(semid1); } if(shmdt(shm_memory)==-1) { perror("error"); exit(0); } if(shmctl(shmid,IPC_RMID,0)) { perror("error"); exit(0); } }
shmread.c
#include<stdio.h> #include<assert.h> #include<stdlib.h> #include<string.h> #include<sys/ipc.h> #include<sys/shm.h> #include<sys/types.h> #include<unistd.h> #include "sem.h" struct shamem { char buff[1000]; }; int main() { void *shm_memory=(void *)0; struct shamem *p; int semid2=sem_get(2233,1); int semid1=sem_get(1122,0); int shmid=shmget((key_t)1234,1024,0664|IPC_CREAT); assert(shmid!=-1); if(shmid==-1) { perror("error\n"); exit(0); } shm_memory=shmat(shmid,NULL,0); if(shm_memory==(void*)-1) { perror("error"); exit(0); } p=(struct shamem *)shm_memory; while(1) { sem_p(semid1); int count=0; if(strncmp(p->buff,"end",3)!=0) { count++; printf("%s\n",p->buff); printf("%d\n",count); p->buff[0]=0; } else { break; } sem_v(semid2); } if(shmdt(shm_memory)==-1) { perror("error"); exit(0); } if(shmctl(shmid,IPC_RMID,0)) { perror("error"); exit(0); } }运行结果:
相关文章推荐
- 进程间通讯 —— 共享内存
- 进程间通讯----消息队列和共享内存方式的实现
- Linux进程间通讯五--共享内存
- 进程间通讯 —— 共享内存
- 进程间通讯--共享内存
- 共享内存实现父子进程间通讯
- 进程间通讯共享内存的具体步骤
- linux进程通讯-共享内存
- Unix/linux 进程间通讯 - 共享内存
- 进程之间的通讯之共享内存
- 进程间通讯概述管道通讯信号通讯共享内存
- linux进程通讯-共享内存1
- 进程间通讯---共享内存
- Linux进程间通讯之共享内存
- linux进程通讯-共享内存
- 进程间通讯——共享内存
- 进程间通讯——消息队列、信号量以及共享内存
- linux进程通讯-共享内存
- 进程间通讯之内存共享(实例)
- 进程间通讯——共享内存