IPC即进程间通信
System V 共享内存
- 共享内存示意图:
由上图可看出共享内存的生命周期一定随内核,所以我们必须手动删除申请的共享内存段。并且共享内存无法提供同步与互斥机制,我们需要自己去维护。不过因为共享内存直接在物理内存中进行操作,不需要多次的相互拷贝,所以它也是进程间通信最快的一种方式。 - 共享内存函数: shm - shared memory
#include<sys/types.h>
#include <sys/ipc.h>
#include<sys/shm.h>
shmget 函数
功能:用来创建共享内存,即在物理内存上开辟空间
原型:int shmget(key_t key,size_t size,int shmflg);
参数:key- 由ftok() 生成的共享内存段的名字
size- 共享内存的大小,以页为单位(1页=4k)
shmflg- 权限标志构成,一般用IPC_CREAT | IPC_EXCL 保证共享内存一定存在
返回值:成功就返回共享内存段的标识码shmid,失败返回-1
ftok()函数可生成共享内存段名字用于唯一标识共享内存段,方便OS管理共享区,同时使两个进程获得同一段共享内存。
shmat 函数
功能:创建进程地址空间与共享内存的映射关系
原型:void *shmat(int shmid,const void *shmaddr,int shmflg);
参数:shmid- 共享内存标识
shmaddr- 指定连接的地址,一般设置为NULL(OS自动分配)
返回值:成功就返回指向共享内存第一个节的指针,失败返回-1
shmdt 函数
功能:将共享内存与当前进程脱离(并非删除共享内存段)
原型:int shmdt(const void*shmaddr);
参数:shmaddr- 由shmat所返回的指针
返回值:成功返回0,失败返回-1
shmctl 函数
功能:控制共享内存可用于删除共享内存段
原型:int shmctl(int shmid,int cmd,struct shmid_ds *buf);
参数:cmd- 将要采取的三个动作(一般用IPC_RMID删除共享内存段)
返回值:成功返回0,失败返回-1
- 实例演示
client.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define PATH "/tmp"
#define PRJ_ID 0x6666
#define SIZE 4096
int main()
{
key_t k=ftok(PATH,PRJ_ID); //得到共享内存段
if(k<0)
{
printf("ftok error\n");
return 1;
}
int shmid=shmget(k,SIZE,0);
if(shmid<0)
{
printf("shmget error\n");
return 2;
}
char *p=(char*)shmat(shmid,NULL,0); //创建映射关系
int i=0;
while(i<SIZE)
{
p[i]='a'+i; //写入共享内存段
i++;
p[i]=0;
sleep(1);
}
shmdt(p); //脱离映射
return 0;
}
server.c
int main()
{
key_t k=ftok(PATH,PRJ_ID);
if(k<0)
{
printf("ftok error\n");
return 1;
}
int shmid=shmget(k,SIZE,IPC_CREAT | IPC_EXCL | 0644); //创建共享内存段
if(shmid<0)
{
printf("shmget error\n");
return 2;
}
char* p=(char*)shmat(shmid,NULL,0); //建立映射
int i=0;
while(i<SIZE)
{
printf("client# %s\n",p); //读取共享区数据
sleep(1);
++i;
}
shmdt(p); //脱离映射
//shmctl(shm_id,IPC_RMID,NULL); //删除IPC资源
return 0;
}
运行结果如下:
但是再次申请共享内存时,发现失败了,原因在于我们没有释放掉原来的共享内存空间。
我们可以通过ipcs -m
看到创建共享内存挂载的两个权限为644的进程。
因此释放共享内存很重要!!
释放共享内存的方法:
用函数在创建共享内存的一端删除:shmctl(shm_id,IPC_RMID,NULL);
用命令在命令行操作:ipcrm -m shmid
这里我们可以了解一下下面两个选项
- 字节 — bytes:因为共享内存以页为单位,所以bytes一般是4096的整数倍
- nattch — 当前共享内存上挂载的进程数,如果一方单独脱离则挂载数会变成1
system V 消息队列
- 消息队列提供了从一个进程向另一个进程发送一块数据的方法
- 每个数据块都被认为有一个类型(用于标识是否自己的数据块),接收者进程接收的数据块可以有不同的类型值
- 特性:IPC资源必须手动删除
- msgget() 可用于创建消息队列
- msgctl() 可用于删除消息队列
system V 信号量
信号量主要用于同步互斥机制。信号量本质是一个用于描述临界资源数目的计数器,所以它在自增(V操作) 自减(P操作)时必须保证原子性。
所谓二元(两种状态)信号量就是指互斥锁。