Linux 进程间通信(六)共享内存

可以说, 共享内存是一种最为高效的进程间通信方式, 因为进程可以直接读写内存, 不需要任何数据的复制。 为了在多个进程间交换信息, 内核专门留出了一块内存区, 这段内存区可以由需要访问的进程将其映射到自己的私有地址空间。 因此, 进程就可以直接读写这一内存区而不需要进行数据的复制, 从而大大提高了效率。 当然, 由于多个进程共享一段内存,因此也需要依靠某种同步机制, 如互斥锁和信号量等(请参考 4.7.2 节)。

其原理示意图如图4.7 所示。

先参考这个博客:

https://blog.csdn.net/tennysonsky/article/details/46425485

共享内存的实现分为两个步骤:

第一步是创建共享内存, 这里用到的函数是 shmget(),也就是从内存中获得一段共享内存区域;

第二步是映射共享内存, 也就是把这段创建的共享内存映射到具体的进程空间中, 这里使用的函数是 shmat()。

到这里, 就可以使用这段共享内存了, 也就是可以使用不带缓冲的 I/O 读写命令对其进行操作。

除此之外, 还有撤销映射的操作, 其函数为 shmdt()。 这里主要介绍这 3 个函数。

在Linux中如何查看ipc对象如何删除ipc对象命令

ipcs -a:查看所有的ipc对象
ipcs -m:查看共享内存
ipcs -q:消息对列
ipcs -s:信号量

删除ipc对象命令:
ipcrm -m  SHM_ID 或ipcrm -M  shm_key
ipcrm -q  MSG_ID 或ipcrm -Q  msg_key
ipcrm -s  SEM_ID 或ipcrm -S  sem_key

shmget()函数的语法要点。

函数原型

int shmget(key_t key, int size, int shmflg)

功能

创建获得共享内存

函数传入值
key: 共享内存的键值, 多个进程可以通过它访问同一个共享内存, 其中有个特殊值
IPC_PRIVATE, 用于创建当前进程的私有共享内存
size: 共享内存区大小
shmflg: 同 open()函数的权限位, 也可以用八进制表示法
函数返回值
成功: 共享内存段标识符
出错: 1

shmat()函数的语法要点。

函数原型

char *shmat(int shmid, const void *shmaddr, int shmflg)
函数传入值
shmid: 要映射的共享内存区标识符
shmaddr: 将共享内存映射到指定地址(若为 0 则表示系统自动分配地址并把该段共享内存映射到调用进程的地址空间)
shmflg:

  1. SHM_RDONLY: 共享内存只读
  2. 默认 0: 共享内存可读写

函数返回值
成功: 被映射的段地址
出错: 1

shmdt()函数的语法要点。

函数原型
int shmdt(const void *shmaddr)
函数参数

shmaddr: 被映射的共享内存段地址

函数返回值
成功: 0
出错: 1

shmctl()函数的语法要点。

函数原型

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

功能

对已存在的共享内存进行控制

函数参数

shmid:共享内存标识

cmd:操作类型

buf:指向操作的信息

返回值

成功返回0,否则返回-1

cmd含义
IPC_STAT获取共享内存的状态
IPC_SET设置共享内存的权限
IPC_RMID删除共享内存
SHM_LOCK锁定共享内存,使共享内存不被置换出去
SHM_UNLOCK对共享内存 解锁

重要结构体:

struct shmid_ds {
               struct ipc_perm shm_perm;    /* 存取权限 */
               size_t          shm_segsz;   /* 共享内存大小 */
               time_t          shm_atime;   /* 最后映射时间 */
               time_t          shm_dtime;   /* 最后删除映射时间 */
               time_t          shm_ctime;   /* 最后修改时间 */
               pid_t           shm_cpid;    /* 创建进程ID */
               pid_t           shm_lpid;    /* 最近操作的进程ID */
               shmatt_t        shm_nattch;  /* 建立映射的进程数 */
               ...
           };
struct ipc_perm {
               key_t          __key;    /* Key supplied to shmget(2) */
               uid_t          uid;      /* Effective UID of owner */
               gid_t          gid;      /* Effective GID of owner */
               uid_t          cuid;     /* Effective UID of creator */
               gid_t          cgid;     /* Effective GID of creator */
               unsigned short mode;     /* Permissions + SHM_DEST and
                                           SHM_LOCKED flags */
               unsigned short __seq;    /* Sequence number */
           };

实例代码:

发送端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
 
#define N 64
 
typedef struct 
{
	pid_t pid;
	char buf[N];
}SHM;
 
void handler(int signo)
{
	//printf("get signal\n");
	return;
}
 
void keycontrol(int signo)
{
	printf("keycontrol is : %d\n",signo);
	if(signo == SIGINT)
	{
		return;
	}
}
 
int main()
{
	key_t key;
	int shmid;
	SHM *p;
	pid_t pid;
 
	//建立IPC通讯,获取key值
	if((key = ftok(".",'m')) < 0)
	{
		perror("fail to ftok");
		exit(-1);
	}
 
 
 
	signal(SIGUSR1,handler);
	signal(SIGINT,keycontrol); 
	// 创建共享内存
	if((shmid = shmget(key,sizeof(SHM),0666|IPC_CREAT|IPC_EXCL)) < 0)
	{//如果创建失败
		if(EEXIST == errno)//如果共享内存已经存在
		{
			shmid = shmget(key,sizeof(SHM),0666);//只是为了获得标识符
			p = (SHM *)shmat(shmid,NULL,0);
			pid = p->pid;
			p->pid = getpid();
			kill(pid,SIGUSR1);
		}
		else
		{
			perror("fail to shmget");
			exit(-1);
		}
	}
	else//如果创建成功
	{
		// 连接共享内存
		p = (SHM*)shmat(shmid,NULL,0);
		p->pid = getpid();
		pause();
		pid=p->pid;
	}
 
	printf("shmid = %d\n",shmid);
	while(1)
	{
		printf("write to shm:");
		fgets(p->buf,N,stdin);
		kill(pid,SIGUSR1);
		if(strcmp(p->buf,"quit\n")==0)
			break;
		pause();
	}
	// 断开连接
	shmdt(p);
	shmctl(shmid,IPC_RMID,NULL);
 
	return 0;
}

接收端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
 
 
#define N 64
 
typedef struct 
{
	pid_t pid;
	char buf[N];
}SHM;
 
void handler(int signo)
{
	//printf("get signal\n");
	return;
}
 
int main()
{
	key_t key;
	int shmid;
	SHM *p;
	pid_t pid;
 
	// 获取key值
	if((key = ftok(".",'m')) < 0)
	{
		perror("fail to ftok");
		exit(-1);
	}
 
	signal(SIGUSR1,handler);
	// 创建共享内存
	if((shmid = shmget(key,sizeof(SHM),0666|IPC_CREAT|IPC_EXCL)) < 0)
	{//如果创建失败
		if(EEXIST == errno)//如果共享内存已经存在
		{
			shmid = shmget(key,sizeof(SHM),0666);//只是为了获得标识符
			p = (SHM *)shmat(shmid,NULL,0);
			pid = p->pid;
			p->pid = getpid();
			kill(pid,SIGUSR1);
		}
		else
		{
			perror("fail to shmget");
			exit(-1);
		}
	}
	else//如果创建成功
	{
		// 连接共享内存
		p = (SHM*)shmat(shmid,NULL,0);
		p->pid = getpid();
		pause();
		pid=p->pid;
	}
 
	while(1)
	{
		pause();
		if (strcmp(p->buf,"quit\n") == 0)
			exit(0);
		printf("read from shm:%s",p->buf);
		kill(pid,SIGUSR1);
	}
 
	return 0;
}

 

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的影城管理系统,源码+数据库+论文答辩+毕业论文+视频演示 随着现在网络的快速发展,网上管理系统也逐渐快速发展起来,网上管理模式很快融入到了许多生活之中,随之就产生了“小徐影城管理系统”,这样就让小徐影城管理系统更加方便简单。 对于本小徐影城管理系统的设计来说,系统开发主要是采用java语言技术,在整个系统的设计中应用MySQL数据库来完成数据存储,具体根据小徐影城管理系统的现状来进行开发的,具体根据现实的需求来实现小徐影城管理系统网络化的管理,各类信息有序地进行存储,进入小徐影城管理系统页面之后,方可开始操作主控界面,主要功能包括管理员:首页、个人中心、用户管理、电影类型管理、放映厅管理、电影信息管理、购票统计管理、系统管理、订单管理,用户前台;首页、电影信息、电影资讯、个人中心、后台管理、在线客服等功能。 本论文主要讲述了小徐影城管理系统开发背景,该系统它主要是对需求分析和功能需求做了介绍,并且对系统做了详细的测试和总结。具体从业务流程、数据库设计和系统结构等多方面的问题。望能利用先进的计算机技术和网络技术来改变目前的小徐影城管理系统状况,提高管理效率。 关键词:小徐影城管理系统;Spring Boot框架,MySQL数据库
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值