033 Android多进程-共享内存

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了033 Android多进程-共享内存相关的知识,希望对你有一定的参考价值。

参考技术A

要使用一块共享内存

还是先看共享内存的使用方法,我主要介绍两个函数:

通过 shmget() 函数申请共享内存,它的入参如下

通过 shmat() 函数将我们申请到的共享内存映射到自己的用户空间,映射成功会返回地址,有了这个地址,我们就可以随意的读写数据了,我们继续看一下这个函数的入参

共享内存的原理是在内存中单独开辟的一段内存空间,这段内存空间其实就是一个tempfs(临时虚拟文件),tempfs是VFS的一种文件系统,挂载在/dev/shm上,前面提到的管道pipefs也是VFS的一种文件系统。

由于共享的内存空间对使用和接收进程来讲,完全无感知,就像是在自己的内存上读写数据一样,所以也是 效率最高 的一种IPC方式。

上面提到的IPC的方式都是 在内核空间中开辟内存来存储数据 ,写数据时,需要将数据从用户空间拷贝到内核空间,读数据时,需要从内核空间拷贝到自己的用户空间,
共享内存就只需要一次拷贝 ,而且共享内存不是在内核开辟空间,所以可以 传输的数据量大

但是 共享内存最大的缺点就是没有并发的控制,我们一般通过信号量配合共享内存使用,进行同步和并发的控制

共享内存在android系统中主要的使用场景是 用来传输大数据 ,并且 Android并没有直接使用Linux原生的共享内存方式,而是设计了Ashmem匿名共享内存

之前说到有名管道和匿名管道的区别在于有名管道可以在vfs目录树中查看到这个管道的文件,但是匿名管道不行, 所以匿名共享内存同样也是无法在vfs目录中查看到 的, Android之所以要设计匿名共享内存 ,我觉得主要是为了安全性的考虑吧。

我们来看看共享内存的一个使用场景,在Android中,如果我们想要将当前的界面显示出来,需要将当前界面的图元数据传递Surfaceflinger去做图层混合,图层混合之后的数据会直接送入帧缓存,送入帧缓存后,显卡就会直接取出帧缓存里的图元数据显示了。

那么我们如何将应用的Activity的图元数据传递给SurfaceFlinger呢?想要将图像数据这样比较大的数据跨进程传输,靠binder是不行的,所以这儿便用到匿名共享内存。

从谷歌官方提供的架构图可以看到,图元数据是通过BufferQueue传递到SurfaceFlinger去的,当我们想要绘制图像的时候, 需要从BufferQueue中申请一个Buffer,Buffer会调用Gralloc模块来分配共享内存 当作图元缓冲区存放我们的图元数据。

可以看到Android的匿名共享内存是通过 ashmem_create_region() 函数来申请共享内存的,它会在/dev/ashmem下创建一个虚拟文件,Linux原生共享内存是通过shmget()函数,并会在/dev/shm下创建虚拟文件。

匿名共享内存是通过 mmap() 函数将申请到的内存映射到自己的进程空间,而Linux是通过*shmat()函数。

虽然函数不一样,但是Android的匿名共享内存和Linux的共享内存在本质上是大同小异的。

多进程取消链接共享内存,需要只有在所有进程退出时才应该取消链接共享内存

【中文标题】多进程取消链接共享内存,需要只有在所有进程退出时才应该取消链接共享内存【英文标题】:multiple process unlinking share memory, need that shared memory should be unlink only when all process exit 【发布时间】:2019-11-26 06:37:50 【问题描述】:

我正在编写一个共享库,它为其读取器和写入器进程提供读/写功能。 Reader 或 Writer 进程可以按任意顺序启动,也可以随时停止然后重新启动。

为了实现两个进程的上述场景,我将共享内存打开为O_CREATE: g_shmfd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);

现在每当一个进程出现故障时,如果我shm_unlink,那么下一次我不想要打开新的共享内存对象。 如果我关闭了解决上述问题的 fd,但共享内存永远不会被此解决方法破坏。 实现多个进程始终打开一个已打开的共享内存对象的最佳方法是什么,并且只有在所有进程shm_unlink 它时才应该销毁它,而不仅仅是调用shm_unlink 销毁对象和下次shm_open 的单个进程创建一个新的共享内存对象。

【问题讨论】:

【参考方案1】:

您可以在shm_open() 和O_CREAT 中设置O_EXCL 标志以检查共享内存对象是否已经存在。如果它已经存在 shm_open 将失败并返回代码EEXIST

EEXIST: O_CREAT 和 O_EXCL 都被指定为 shm_open()name 指定的共享内存对象已经存在。

【讨论】:

谢谢,我正在寻找的是,当一个进程退出并调用 shm_unlink 时,它会销毁 shm 对象,但只有在所有进程都退出时才应销毁它。

以上是关于033 Android多进程-共享内存的主要内容,如果未能解决你的问题,请参考以下文章

多进程取消链接共享内存,需要只有在所有进程退出时才应该取消链接共享内存

android匿名共享内存原理浅读

Android native进程间通信实例-binder结合共享内存

37. Python 多进程锁 多进程共享内存

Gunicorn 在多处理进程和工作进程之间共享内存

python学习笔记——多进程中共享内存Value & Array