1.概念:
共享内存是System V版本的最后一个进程间通信方式。共享内存,顾名思义就是允许两个不相关的进程访问同一个逻辑内存,共享内存是两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常为同一段物理内存。进程可以将同一段物理内存连接到他们自己的地址空间中,所有的进程都可以访问共享内存中的地址。如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。
特别提醒:共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取,所以我们通常需要用其他的机制来同步对共享内存的访问,例如信号量。
2.共享内存的通信原理
在Linux中,每个进程都有属于自己的进程控制块(PCB)和地址空间(Addr Space),并且都有一个与之对应的页表,负责将进程的虚拟地址与物理地址进行映射,通过内存管理单元(MMU)进行管理。两个不同的虚拟地址通过页表映射到物理空间的同一区域,它们所指向的这块区域即共享内存。
共享内存的通信原理示意图:
对于上图我的理解是:当两个进程通过页表将虚拟地址映射到物理地址时,在物理地址中有一块共同的内存区,即共享内存,这块内存可以被两个进程同时看到。这样当一个进程进行写操作,另一个进程读操作就可以实现进程间通信。但是,我们要确保一个进程在写的时候不能被读,因此我们使用信号量来实现同步与互斥。
对于一个共享内存,实现采用的是引用计数的原理,当进程脱离共享存储区后,计数器减一,挂架成功时,计数器加一,只有当计数器变为零时,才能被删除。当进程终止时,它所附加的共享存储区都会自动脱离。
为什么共享内存速度最快?
借助上图说明:Proc A 进程给内存中写数据, Proc B 进程从内存中读取数据,在此期间一共发生了两次复制
(1)Proc A 到共享内存 (2)共享内存到 Proc B
因为直接在内存上操作,所以共享内存的速度也就提高了。
3.如何使用共享内存
1)创建共享内存(shmget)
2)访问共享内存(shmat,每一个进程必须绑定到自己的地址空间)
3)解除绑定(shmdt)
4)释放共享内存(shmctl,由一个进程释放即可)
4.相关函数
1.shmget()
2.shmat()
3.shmdt()
4.shmctl()
共享内存-父子进程间的通讯
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SHM_KEY 11
typedef struct{
int type;//>0
char dat[100];
}SM;
int main(){
SM *smp;
printf("size:%d\n",sizeof(SM));
int shmid = shmget(SHM_KEY,sizeof(SM),0644|IPC_CREAT);
if(shmid == -1){
perror("shmget error!\n");
exit(1);
}
smp = shmat(shmid,NULL,0);
if(smp == (void*)-1){
perror("shmat error!\n");
exit(1);
}
printf("share memory allocate successful!\n");
pid_t pid = fork();
if(pid == -1){
perror("fork error!\n");
exit(1);
}
if(pid == 0){
//read
while(1){
if(strlen(smp->dat) == 0){
sleep(1);
continue;
}
printf("receive %s\n",smp->dat);
if(strcmp(smp->dat,"exit") == 0){
break;
}
memset(smp,0,sizeof(SM));
}
if(shmdt(smp) == -1){
perror("shmid error!\n");
exit(1);
}
if(shmctl(shmid,IPC_RMID,NULL) == -1){
perror("shmctl error!\n");
exit(1);
}
printf("remove shm successful!\n");
}else if(pid > 0){
//write
while(1){
scanf("%s",smp->dat);
if((strcmp(smp->dat,"exit") == 0)){
break;
}
}
if(shmdt(smp) == -1){
perror("parent:shmdt error!\n");
exit(1);
}
sleep(3);
}
return 0;
}
共享内存-无关进程间的通信
信号量
在看信号量之前,我们先来看几个概念:
(1)临界资源:多个进程看到的同一个资源(公共资源);
(2)临界区:访问临界资源的代码;
(3)同步性:在一段时间内,按照一定的顺序访问 ;
(4)互斥性:在一段时间内,一份资源只能被一个进程访问 和占用 ;
(5)原子性: 一个事物要么全做,要么不做,不能只做一半 ;
1. 信号量的概念
(1)信号量本质上是计数器,是衡量临界资源的数量的 ;
(2)信号量也是一种临界资源,它的作用是保护临界资源 ;
(3)信号量只有两种操作,PV原语,P表示申请资源(上锁),V表示释放资源(解锁);//上锁就是能利用cpu资源对公共资源进行访问 //解锁就是即使得到cpu资源也访问不了
2.使用步骤
1)进程调用semget函数创建新的信号量集合,或者获取已有得到信号量集合。
2)调用semctl函数给集合中的每个信号量设置初值。
3)调用semop函数对集合中的信号量进行PV操作。(P加锁:对信号量-1,如果信号量的