UNIX共享内存总结

    共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。因此,采用共享内存的通信方式效率是非常高的。

 

【应用场景】

 

1. 进程间通讯-生产者消费者模式

 

    生产者进程和消费者进程通讯常使用共享内存,比如一个网络服务器,接入进程收到数据包后,直接写到共享内存中,并唤醒处理进程,处理进程从共享内存中读数据包,进行处理。当然,这里要解决互斥的问题。

 

2. 父子进程间通讯

 

    由于fork产生的子进程和父进程不共享内存区,所以父子进程间的通讯也可以使用共享内存,以POSIX共享内存为例,父进程启动后使用MAP_SHARED建立内存映射,并返回指针ptr。fork结束后,子进程也会有指针ptr的拷贝,并指向同一个文件映射。这样父、子进程便共享了ptr指向的内存区。

 

3. 进程间共享-只读模式

 

    业务经常碰到一种场景,进程需要加载一份配置文件,可能这个文件有100K大,那如果这台机器上多个进程都要加载这份配置文件时,比如有200个进程,那内存开销合计为20M,但如果文件更多或者进程数更多时,这种对内存的消耗就是一种严重的浪费。比较好的解决办法是,由一个进程负责把配置文件加载到共享内存中,然后所有需要这份配置的进程只要使用这个共享内存即可。

 

【共享内存分类】

 

1. POSIX共享内存对象

 

const char shmfile[] = "/tmp";
const int size = 100;

 

shm_open创建一个名称为tmp,大小为100字节的共享内存区对象后,在/dev/shm/下可以看到对应的文件,cat可以看到内容。

root:/home/#ls -al /dev/shm/tmp
-rw------- 1 root root 100 10-15 13:37 /dev/shm/tmp

 

访问速度:非常快,因为 /dev/shm 是tmpfs的文件系统, 可以看成是直接对内存操作的,速度当然是非常快的。

 

持续性:随内核,即进程重启共享内存中数据不会丢失,内核自举或显示调用shm_unlink或rm掉文件删除后丢失。

 

2.  POSIX内存映射文件

const char shmfile[] = "./tmp.shm";
const int size = 100;

 

open在指定目录下创建指定名称后文件,cat可以看到内容。

root:/home/#ls -al ./tmp.shm

-rw-------  1 root    root    100 10-15 13:42 tmp.shm

 

访问速度:慢于内存区对象,因为内核为同步或异步更新到文件系统中,而内存区对象是直接操作内存的。

持续性:随文件,即进程重启或内核自举不后丢失,除失显示rm掉文件后丢失。

 

3. SYSTEM V共享内存

 

共享内存创建后,执行ipcs命令,会打印出相应的信息,比如下面所示,key为申请时分配的,可以执行ipcrm -M 0x12345678 删除,nattch字段为1表示有一个进程挂载了该内存。

 

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status     
0x12345678 32769      root      644        10         1

 

访问速度:非常快,可以理解为全内存操作。

持续性: 随内核,即进程重启共享内存中数据不会丢失,内核自举或显示调用shmdt或使用ipcrm删除后丢失。

 

与POSIX V共享内存区对象不同的是,SYSTEM V的共享内存区对象的大小是在调用shmget创建时固定下来的,而POSIX共享内存区大小可以在任何时刻通过ftruncate修改。

 

 

【代码示例】

 

下面给出三种共享内存使用方法的示例代码,都采用父子进程间通讯,并未考虑互斥,仅做示例供大家参考。

 

1.POSIX共享内存对象

  

 

 

编译执行

root:/home/ftpuser/ipc#g++ -o shm_posix -lrt shm_posix.cc     
root:/home/ftpuser/ipc#./shm_posix
Child 2280: start

There is 3 item in the shm
1: Nellson
2: Daisy
3: Robbie

Parent 2279 get child status:0

 

2.POSIX文件映射

 

 

编译执行

 

root:/home/ftpuser/ipc#g++ -o map_posix map_posix.cc
root:/home/ftpuser/ipc#./map_posix
Child 2300: start

There is 3 item in the shm
1: Nellson
2: Daisy
3: Robbie

Parent 2299 get child status:0

 

3.SYSTEM V 共享内存对象

 

 

编译执行

 

root:/home/ftpuser/ipc#g++ -o shm_v shm_v.cc 
root:/home/ftpuser/ipc#./shm_v
Child 2323: start

There is 3 item in the shm
1: Nellson
2: Daisy
3: Robbie

Parent 2322 get child status:0

 

【性能测试】

下面对三种方式进行性能测试,比较下差异。

测试机信息:

AMD Athlon(tm) Neo X2 Dual Core Processor 6850e

cpu:1.7G

os: Linux 2.6.18

 

测试方式:

打开大小为SIZE的共享内存,映射到一个int型的数组中,循环写数组、读数组。

重复10W次,计算时间开销。

 

内存大小

Shmopen+mmap(ms)

Open+mmap

Shmget

4k

1504

1470

1507

16k

6616

6201

5994

64k

25905

24391

24315

256k

87487

76981

69417

1M

253209

263431

241886

 

重复1K次,计算时间开销。

 

内存大小

Shmopen+mmap(ms)

Open+mmap(ms)

Shmget(ms)

1M

5458

5447

5404

4M

21492

21447

21307

16M

90880

93685

87594

32M

178000

214900

193000

 

分析:

Sytem V方式读写速度快于POSIX方式,而POSIX 共享内存和文件映射方式相差不大, 共享内存性能略优。

 

附上测试源码:

  

 

 

 

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值