Пишем в ашмем / почему андроид бесплатно ашмем?
Я хочу делиться данными между двумя (ndk-) процессами. Для этого я использую Ashmem, используя этот источник.
Один процесс постоянно читает (read_mem
) и один процесс пишет один раз (write_mem
).
Проблема в том, что процесс чтения не получает значения автора.
А ТАКЖЕ
Просматривая карты ридера, я обнаружил, что Android удаляет файл общей памяти сразу после ashmem_create_region
,
read_mem.c
// 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
// 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;
}
Это вывод:
чтение
130|shell@mako:/data/local/tmp $ ./read_mem
ashmem_create_region: 3
PID=29655
VALUE = 0x0
Пишу
shell@mako:/data/local/tmp $ ./write_mem
ashmem_create_region: 3
PID=29691
A
Written 0x41
Чтение снова VALUE = 0x0
(нажав возврат)
Смотря карты читателя:
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
это существует.
ашмем взят отсюда
1 ответ
Ashmem не работает как обычная общая память в Linux, и этому есть веская причина.
Во-первых, давайте попробуем объяснить "(удаленную)" часть, это деталь реализации того, как ashmem реализован в ядре. На самом деле это означает, что запись файла была создана в каталоге / dev / ashmem /, а затем удалена, но соответствующий i-узел все еще существует, поскольку для него существует хотя бы один открытый дескриптор файла.
На самом деле вы можете создать несколько областей Ashmem с одним и тем же именем, и все они будут отображаться как "/ dev / ashmem /
Вот почему название области ашмем действительно используется только для отладки. Невозможно "открыть" существующий регион по имени.
I-узел ashmem и соответствующая память автоматически освобождаются, когда закрывается последний дескриптор файла. Это полезно, потому что это означает, что если ваш процесс умирает из-за сбоя, ядро автоматически восстанавливает память. Это не относится к обычной разделяемой памяти SysV (сбойный процесс просто приводит к утечке памяти! Что-то недопустимое во встроенной системе, такой как Android).
Ваши тестовые программы создают две разные области ашмэма с одинаковыми именами, поэтому они не работают так, как вы думаете. Вместо этого вам нужно:
1) Создайте одну область ашмэма в одном процессе.
2) Передать новый файловый дескриптор в область от первого процесса ко второму.
Один из способов сделать это - форкать первый процесс для создания второго (это автоматически продублирует дескрипторы файлов), но это обычно не очень хорошая идея для Android.
Лучшая альтернатива - использовать sendmsg() и recvmsg() для отправки дескриптора файла через сокет Unix-домена между двумя процессами. Это, как правило, сложно, но в качестве примера рассмотрим функции SendFd() и ReceiveFd() в следующем исходном файле, написанном для NDK:
Вуаля, надеюсь, это поможет