加载中…
个人资料
IT傻孩子
IT傻孩子
  • 博客等级:
  • 博客积分:0
  • 博客访问:2,282
  • 关注人气:27
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
谁看过这篇博文
加载中…
正文 字体大小:

跟我一起学Linux(五)进程间通讯之【共享内存】

(2017-11-19 15:09:55)
标签:

365

it

分类: LINUX
进程间通讯之共享内存
一、引言:

管道、信号、信号量虽然满足了进程之间通讯的需要,但是还有一种没有满足,那就是进程之间需要共享大量的数据。就像一家人一样,他们彼此之间每天都在交流,但是对于家里面的一些共有物品,如电视,餐厅等等都是共享的,而我们所说的进程之间也是一样的,他们虽然互相独立存在,但是还有很多数据都是共享使用的,而进程之间的数据共享就是共享内存。

二、共享内存理论及其分析:

共享内存就是两个进程共同拥有同一片内存区域。这片区域中的内容,二者都可以访问。要使用共享内存进行通讯,一个进程首先创建一片内存空间专门作为通信使用,而其他的进程则将这片内存空间映射到自己的(虚拟)地址空间。这样就通过读写自己地址空间中对应的的共享内存区域时,就是在和其他的进程进行通信了。

通过这里的了解,是不是感觉共享内存和我们前面博客讲的管道很像呢,管道也是在一片内存区域上作为进程间通信的媒介,但是这里的共享内存和管道是不一样的,首先,使用共享内存时两个进程必须在同一台物理机器上,其次,共享内存的访问方式是随机的,而不是只能从一端写,另一端写,因此这也是共享内存的一大优点,所以共享内存传递的信息也比较多,随之而来大量信息的传递也使得传递时比较复杂。
如图所示,共享内存的图解:
跟我一起学Linux(五)进程间通讯之【共享内存】
那么共享内存与管道,信号量,信号等等通信有啥区别呢?
共享内存是最快的一种IPC通信方式,在各个进程都有指针指向开辟出来的内存区域,访问的时候当做进程中的一个内存控制直接操作,也就是说对于一个内存而言,共享内存就是进程的一部分,直接通过指针操作这片区域,少了内核的陷入过程;进程直接通过指针操作共享内存区域,少了用户态和内核态之间数据的拷贝。
区别图解:
跟我一起学Linux(五)进程间通讯之【共享内存】

但是共享内存也有它的缺点:由于共享内存是进程中通信最快的的,且信息量较大,也造成了它的管理复杂,且两个进程必须在同一台物理机器上才能进行通讯,另外一个缺点就是,安全性低,当两个进程共享一片内存区域进行通讯时,如果一个进程感染了病毒,很容易会传给(感染)另外一个进程。就像一家人一样,一个人感冒了,有些东西是公用的,到时候用的时候会很容易感染给别人,这是同样的道理。
再就是需要注意的是:使用全局变量在同一个进程的线程间实现通信不叫共享内存,它们是使用进程中的资源,线程只是进程内部的一个执行序列,后期将会进行分析说明。

共享内存使用时,是一个临界资源,所以进程之间使用必须做同步控制,而这里能更好的达到同步控制需要利用我们前面所说的信号量。

三、共享内存的使用函数:

头文件:
#include
头文件sys/types.h和sys/ipc.h被shm.h自动包含进程序。

shmget函数:
创建共享内存,获得一个共享内存标识符;
int shmget(key_t key,  size_t size,  int shmflg);
第一个参数是程序提供的一个键值,为共享内存命名,shmget函数返回一个共享内存标识符,后面的其他函数会使用。
第二个参数:size以字节为单位指定需要共享的内存容量。
第三个参数:如果共享内存存在则获取,不存在,使用IPC_CREAT创建,创建可以给设置权限标志 Onnn,这样允许创建共享内存的进程写入数据,设置其他的用户创建的进程只能以读取该共享内存。
返回值:创建成功,返回一个非负整数,即共享内存标识符,失败,则返回-1.

shmat函数:
将共享内存的段连接到进程的地址空间中。
void *shmat(int shm_id,  const *shm_addr,  int shmflg);
第一个参数shm_id是shmget函数的返回的共享内存标识符。
第二个参数shm_addr是:共享内存将要连接到当前进程中的地址位置,它通常是一个NULL,表示让系统来选择共享内存出现的地址。
第三个参数shmflg:是一组位标志,取值为:SHM_RND与shm_addr联合使用用来控制共享内存区域连续的地址        和SHM_RDONLY(它使得连续的内存只读)。
返回值:如果shmat调用成功,返回一个指向共享内存第一个字节的指针,如果失败,则返回-1.

shmdt函数:
断开连接;此函数只会断开连接,而不会删除共享内存。
int shmdt(void *addr);
addr参数是以前调用shmat函数的时的返回值,如果成功,shmdt将相关shmid_ds结构中的shm_nattch计数器值减1.
返回值:成功返回0,失败返回-1.
跟我一起学Linux(五)进程间通讯之【共享内存】
shmctl函数:
删除内核对象;
int shmctl(int shm_id,  int command,  struct shmid_ds *buf);
shmid_ds结构:
struct shmid_ds
{
uid_t  shm_perm.uid;
uid_t  shm_perm.gid;
mode_t  shm_perm.mode;
}
第一个参数shm_id是shmget返回的共享内存标识符
第二个参数command是要采取的动作,取以下三个值:
IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值
IPC_SET :如果进程有足够权限,把共享内存的当前关联值设置为shmid_ds结构中的值;
IPC_RMID:删除共享内存段;
第三个参数buf是一个指针,它指向包含共享内存模式和访问权限的结构。
返回值:成功时返回0;失败时返回-1;

基于intel的Linux系统上的存储区布局:
跟我一起学Linux(五)进程间通讯之【共享内存】

四、共享内存的测试题:

题目:A进程接收用户输入,B进程统计字符个数,遇到end结束!
代码如下:
信号量sem.c中信号量初始值为1;data.val = 1;,其他信号量封装函数见《跟我一起学Linux(五)进程间通讯之【信号量】》
跟我一起学Linux(五)进程间通讯之【共享内存】
文件:shma.c
跟我一起学Linux(五)进程间通讯之【共享内存】
文件:shmb.c
跟我一起学Linux(五)进程间通讯之【共享内存】

Linux终端下编译命令:
shma.c文件:gcc -o  shma   shma.c  sem.c
shmb.c文件:gcc -o  shmb   shmb.c  sem.c

结果:
A进程用户:
跟我一起学Linux(五)进程间通讯之【共享内存】
B进程计算:
跟我一起学Linux(五)进程间通讯之【共享内存】
测试目的:为了更好的使用共享内存进行进程间的通讯,以及对于进程间使用共享内存熟练使用,得到加强,并且融入信号量,进程对共享内存访问时,是同步控制的。

连载中跟我一起学Linux(五)进程间通讯之【共享内存】

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有