【Linux】进程间通信——System V IPC

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操作)时必须保证原子性。
所谓二元(两种状态)信号量就是指互斥锁。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值