首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >给ashmem写信/ android为什么免费使用ashmem?

给ashmem写信/ android为什么免费使用ashmem?
EN

Stack Overflow用户
提问于 2015-01-08 10:10:07
回答 1查看 13.7K关注 0票数 7

我想在两个(ndk-)进程之间共享数据。为此,我使用了使用这个来源的ashmem。

一个进程是连续读取(read_mem),另一个进程是写入一次(write_mem)。

问题是读取过程没有得到作者的值。

通过查看阅读器的地图,我发现Android会在ashmem_create_region之后删除共享内存文件。

read_mem.c

代码语言:javascript
复制
// read_mem.c
#include <stdio.h>
#include <errno.h>
#include <sys/mman.h>
#include "ashmem.h"

#define SHM_NAME "test_mem"
int main(int argc, char **argv) {
    int shID = ashmem_create_region(SHM_NAME, 2);
    if (shID < 0)
    {
        perror("ashmem_create_region failed\n");
        return 1;
    }
    // right here /dev/ashmem/test_mem is deleted
    printf("ashmem_create_region: %d\n", shID);
    char *sh_buffer = (char*)mmap(NULL, 2, PROT_READ | PROT_WRITE, MAP_SHARED, shID, 0);
    if (sh_buffer == (char*)-1)
    {
        perror("mmap failed");
        return 1;
    }
    printf("PID=%d", getpid());
    do
    {
        printf("VALUE = 0x%x\n", sh_buffer[0]);
    }
    while (getchar());
    return 0;
}

write_mem.c

代码语言:javascript
复制
// write_mem.c
#include <stdio.h>
#include <errno.h>
#include <sys/mman.h>
#include "ashmem.h"

#define SHM_NAME "test_mem"
int main(int argc, char **argv) {
    int shID = ashmem_create_region(SHM_NAME, 2);
    if (shID < 0)
    {
        perror("ashmem_create_region failed\n");
        return 1;
    }
    printf("ashmem_create_region: %d\n", shID);
    char *sh_buffer = (char*)mmap(NULL, 2, PROT_READ | PROT_WRITE, MAP_SHARED, shID, 0);
    if (sh_buffer == (char*)-1)
    {
        perror("mmap failed");
        return 1;
    }
    printf("PID=%d\n", getpid());
    int ch = getchar();
    sh_buffer[0] = ch;
    printf("Written 0x%x\n", ch);
    munmap(sh_buffer, 2);
    close(shID);
    return 0;
}

这是输出:

阅读

代码语言:javascript
复制
130|shell@mako:/data/local/tmp $ ./read_mem
ashmem_create_region: 3
PID=29655
VALUE = 0x0

写作

代码语言:javascript
复制
shell@mako:/data/local/tmp $ ./write_mem
ashmem_create_region: 3
PID=29691
A
Written 0x41

再次读取VALUE = 0x0 (按返回)

看读者的地图:

代码语言:javascript
复制
shell@mako:/ $ cat /proc/29655/maps | grep test_mem
b6ef5000-b6ef6000 rw-s 00000000 00:04 116213     /dev/ashmem/test_mem (deleted)

如您所见,test_mem被删除, read_mem还活着时被删除。

其他信息

这两个文件都使用android ndk-build命令编译为可执行文件。

设备: LG Nexus 4 (AOSP Lollypop)

我检查了/dev/ashmem它的存在。

这里取来的灰烬

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-01-08 22:35:12

Ashmem的工作方式与Linux上的常规共享内存不同,这是一个很好的理由。

首先,让我们尝试解释“(删除)”部分,这是在内核中如何实现ashmem的实现细节。真正的意思是在/dev/ashmem/目录中创建了一个文件条目,然后删除,但是相应的i节点仍然存在,因为它至少有一个打开的文件描述符。

实际上,您可以使用相同的名称创建多个ashmem区域,它们都将显示为"/dev/ashmem/ (已删除)“,但每个区域都对应于不同的i节点,因此对应于不同的内存区域。如果您在/dev/ashmem/下面查看,您会发现目录仍然是空的。

这就是为什么一个ashmem区域的名称实际上只用于调试。没有办法按名称“打开”现有的区域。

当关闭该节点的最后一个文件描述符时,将自动回收一个ashmem i节点和相应的内存。这很有用,因为这意味着如果进程因崩溃而死亡,内核将自动回收内存。对于常规的SysV共享内存,情况并非如此(崩溃的过程只是泄漏内存!)在像Android这样的嵌入式系统上是不可接受的。

您的测试程序创建了两个具有相同名称的不同的ashmem区域,这就是为什么它们不像您所认为的那样工作。你所需要的是:

1)在一个过程中创建一个单一的灰域。

2)将新的文件描述符从第一个进程传递到第二个进程到该区域。

其中一种方法是分叉第一个进程来创建第二个进程(这将自动复制文件描述符),但在Android环境下,这通常不是一个好主意。

更好的选择是使用sendmsg()和recvmsg()通过两个进程之间的Unix域套接字发送文件描述符。这通常是很棘手的,但是作为一个例子,看看下面的源文件中的SendFd()和ReceiveFd()函数是为NDK编写的:

util.h

瞧,希望这能帮上忙

票数 32
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27837507

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档