当前位置:首页 > 嵌入式培训 > 嵌入式学习 > 讲师博文 > 进程之间的通讯之共享内存

进程之间的通讯之共享内存 时间:2018-09-26      来源:未知

一. 简介

刚刚我们了解了我们的IPC对象,我们知道我们的System V进程间的通信,在系统建立IPC通信的时候,必须指定一个ID值。而该ID的值,我们就可以通过ftok()函数来间接的得到。共享内存就是我们的进程间的一种通信方式。

顾名思义,共享内存就是就是允许两个不相关的进程访问同一个物理内存。可以理解为多个进程共享同一块物理内存。共享内存是进程间共享数据的一种快的方法,进程可以将相同的物理内存,映射到不同的虚拟地址空间中。所有的进程都可以访问共享内存中的数据。可以理解为C语言的malloc分配了一个空间,定义两个指针变量保存了堆区的空间一样。如果一个进行向共享内存中写入了数据,那么它的举动会影响到可以访问同一段内存的其他进程。如下图所示。

二. 共享内存的实现步骤

我们的共享内存的操作步骤分为以下四步:

<1>创建共享内存

<2>映射共享内存,即把指定的共享内存映射到多个进程的地址空间,方便进程的访问。

<3>撤销共享内存的映射

<4>删除共享内存

1)创建共享内存 ,既然叫做共享内存,顾名思义,肯定是share memory 的缩写。函数如下。

#include

#include

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

功能:申请一块指定大小共享内存

参数:

@ key IPC_PRIVATE : 用于亲缘间进程的通信

ftok()函数获得: 用于非亲缘关系的进程

@size 申请共享内存的大小

(注:所有的内存分配时以也4K的倍数为大小进行分配的。即如果一个进程申 请了1块只有1byte的内存,操作系统也会给该内存分配4096bytes。但是真正能够使用的只有1byte。 )

@shmflg 权限标志 (常用如下)。

IPC_CREAT | 0666 如果共享内存不存在,则创建一个共享内存,否则直接打开已存在的,返回其ID。

IPC_CREAT | IPC_EXCL |0666 只有在共享内存不存在的时候,新的共享内存才建立,否则若是存在,shmges调用失败,并设置EEXITST错误码。

返回值:

成功返回共享内存的id号,失败返回-1

查看IPC对象

ipcs –m 显示共享内存段的信息

ipcs -q 显示消息队列段的信息

ipcs -s 显示信号灯集段的信息。

删除IPC对象

ipcrm -m/-q/-s ID

理解方法:可以想象成我们使用open函数打开一个文件的时候,若是使用O_CREAT | O_EXECL,0666,若是文件存在,则显示打开失败。

练习:

自己利用ftok()函数创建一个key值,然后利用shmget()创建共享内存。

如果共享内存存在则报错,不存在则创建。自己利用ipcs命令查看共享内存信息。

2)映射共享内存,把共享内存和进程的地址空间联系起来。(share memeor attach)

手册阅读:

翻译:

<1>函数功能及参数

shmat() 函数映射一个共享内存段,把它和由当前进程调用的由shmid参数指定的地址空间联系起来。

这个指定的地址空间,由shmaddr下列选择指定:

如果 shmaddr 是NULL,操作系统选择一个合适的(未使用的)共享内存段。

如果SHM_RDONLY 被shmflag标志指定,这个被映射的进程的地址空间必须拥有读权限。另一方面,段连接的地址空间若是想要读写的话,必须要有读和写的权限。没有一个只写概念的共享内存段。

<2>返回值

Shamt()函数成功返回共享内存映射的地址空间,失败返回(void *)-1并设置error

<3>映射共享内存,把共享内存和进程的地址空间联系起来。

void * shmat(int shmid, const void *shmaddr, int shmflg);

功能:把shmid创建共享内存块附加到进程的私有地址。[进程的虚拟地址空间]

参数:

@ shmid 共享内存段的标识 [由shmget()函数得到]

@ shmaddr[将共享内存映射到指定的地址空间]

NULL 让系统自动完成映射

@ shmflg[映射的标志] 0 映射可以读写;

SHM_RDONLY 映射后只能读

返回值:成功返回映射后的进程的地址空间

失败返回(void *)-1,并且置errno

注意:进程结束之后,共享内存的映射自动撤销。

3)撤销共享内存。

int shmdt (const void * shmaddr);

功能:撤销共享内存到进程地址空间的映射

参数:

@smaddr 共享内存映射到进程指定的地址空间

返回值:

成功返回 0

失败返回 -1, 并且置errno

注:给shmdt传递的地址必须是shmat()函数获得的。

4)删除共享内存。[shmat control]

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

功能:对共享内存进行控制

参数:

@shmid 共享内存段的标识 [由shmget()函数得到]

@cmd 共享内存的控制命令

IPC_RMID 删除共享内存。

@buf shmid 的一些信息。

NULL 表示不需要使用它。

返回值:

成功返回0,失败返回-1

//结构体简介 [了解即可]

struct shmid_ds

{

struct ipc_perm shm_perm;/* 操作权限*/

int shm_segsz; /*段的大小(以字节为单位)*/

time_t shm_atime; /*后一个进程附加到该段的时间*/

time_t shm_dtime; /*后一个进程离开该段的时间*/

time_t shm_ctime; /*后一个进程修改该段的时间*/

unsigned short shm_cpid; /*创建该段进程的pid*/

unsigned short shm_lpid; /*在该段上操作的后1个进程的pid*/

short shm_nattch; /*当前附加到该段的进程的个数*/

/*下面是私有的*/

unsigned short shm_npages; /*段的大小(以页为单位)*/

unsigned long *shm_pages; /*指向frames->SHMMAX的指针数组*/

struct vm_area_struct *attaches; /*对共享段的描述*/

};

IPC_RMID 破化共享内存段。

代码演示:

运行结果:

练习:利用共享内存实现两个进程间的shm_read.C和shm_write.C之间的通信。

[注意:两个进程只要打开的是同一个文件路径,则获得相同的共享内存。]

思路:

shm_read.c

//接收写进程的信号

Signal(SIGUSR1,signal_handler)

{

}

//创建共享内存

Shget

//内存映射

Shmat

通过getpid()得到自己的pid号写到共享内存中,让write进程获取。

*(int *)paddr = getpid();

//循环把数据写到共享内存中去

While(1)

{

Pause();//修改等待写进程书写完毕,接收信号。

Read();

}

//撤销进程

//删除共享内存

shm_write.c

//创建共享内存

Shget

//内存映射

Shmat

//获得read进程的pid号,以便于向read进程发送信号

Pid = *(int *)paddr;

While(1)

{

putchar(‘>’);

fgets();

//书写完毕发送信号。

kill(pid,SIGUSR1);

}

//解除映射

//删除共享内存

注意:由于write进程要获得read进程的pid号,故要求read进程先运行,write进程后运行。

上一篇:进程间通信方式汇总

下一篇:html入门学习

热点文章推荐
华清学员就业榜单
高薪学员经验分享
热点新闻推荐
前台专线:010-82525158 企业培训洽谈专线:010-82525379 院校合作洽谈专线:010-82525379 Copyright © 2004-2022 北京华清远见科技集团有限公司 版权所有 ,京ICP备16055225号-5京公海网安备11010802025203号

回到顶部