进程通信:进程与进程间的数据交换,称为进程通信。进程通讯的方式有:共享内存、信号量、管道、消息队列、socket等等。
共享内存:内核管理一片物理内存,允许不同的进程同时映射,多个进程可以映射同一块内存,被多个进程同时映射的物理内存,即共享内存。映射物理内存叫挂接,用完以后解除映射叫脱接。
优点:共享内存是进程通讯最快最有效的。
缺点:不存在同步机制,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取,需与其他机制合作来实现同步。
共享内存有两种方式:mmap、shm。
mmap:mmap方式是将文件与进程地址空间进行映射,对实际物理内存影响小。mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问,不必再调用read,write等操作。即在磁盘上建立一个文件,每个进程地址空间中开辟出一块空间进行映射。
shm:shm方式是将每个进程的共享内存与实际物理存储器进行映射,对实际物理内存影响大。即每个进程最终会映射到同一块物理内存。shm保存在物理内存,这样读写的速度要比磁盘要快,但是存储量不是特别大。
shm实现步骤:
- fork(),获得一个key
- shmget(),用key来创建共享内存
- shmat(),映射共享内存,得到虚拟地址
- 用共享内存读或者写
- shmdt(),解除映射关系
- shmctl(),销毁共享内存
例子如下:shm_test1.c:写入数据 shm_test2.c:读数据
//--------------------------------写入数据---------------------------------
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include<sys/shm.h>
#include <sys/types.h>
int shm_id;
char *buff = NULL;
void fina_l(int signo)
{
shmctl(shm_id,IPC_RMID,NULL);
return ;
}
int main(int argc, char *argv[])
{
int i = 0;
int k = 0;
key_t shm_key;
system("> shm.txt");
signal(SIGINT,fina_l);
signal(SIGTERM,fina_l);
//将指定文件,shm.txt转换成我们所需要的key,该文件必须存在且可存取,名字和数字相同就会产生相同的key,数字必须大于0
shm_key = ftok("shm.txt",1);
if(shm_key == -1){
printf("ftok is fail\n");
return -1;
}
shm_id = shmget(shm_key,20,IPC_CREAT|IPC_EXCL|0777); //用key来创建共享内存
if(shm_id == -1)
{
printf("shmget is fail\n");
return -1;
}
for(i=0;i<3;i++)
{
buff = (char*)shmat(shm_id,NULL,0); //映射共享内存,得到虚拟地址
strcpy(buff,"hello,is me!!!");
shmdt(buff); //解除共享内存
}
return 0;
}
//--------------------------------读数据---------------------------------
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include<sys/shm.h>
#include <sys/types.h>
int shm_id;
char *buff = NULL;
void fina_l(int signo)
{
shmctl(shm_id,IPC_RMID,NULL);
return ;
}
int main(int argc, char *argv[])
{
int i = 0;
int k = 0;
key_t shm_key;
system("> shm.txt");
signal(SIGINT,fina_l);
signal(SIGTERM,fina_l);
sleep(2);
//将指定文件,shm.txt转换成我们所需要的key,该文件必须存在且可存取,名字和数字相同就会产生相同的key,数字必须大于0
shm_key = ftok("shm.txt",1);
if(shm_key == -1){
printf("ftok is fail\n");
return -1;
}
shm_id = shmget(shm_key,20,0);//用key来创建共享内存,0表示shm_key映射不存在,则会报错
if(shm_id == -1)
{
printf("shmget is fail\n");
return -1;
}
for(k=0;k<3;k++)
{
buff = (char *)shmat(shm_id,NULL,0); //映射共享内存,得到虚拟地址
printf("number: %d buff is: %s\n",k,buff);
shmdt(buff); //解除共享内存
sleep(1);
}
shmctl(shm_id,IPC_RMID,NULL); //销毁共享内存
return 0;
}
结果如下:
总结:一般来说mmap方式是将文件与进程地址空间进行映射,对实际物理内存影响小,操作简单,重启会保存操作系统同步的映像和本身的文件,shm方式是将每个进程的共享内存与实际物理存储器进行映射,对实际物理内存影响大,所以一般用mmap会比较好。