Многопроцессорность с помощью Android NDK SharedMemory.h - PullRequest
0 голосов
/ 30 октября 2018

Я продолжаю пробовать мультиобработку (с использованием общей памяти) в Android Studio (с NDK). Я установил NDK, LLDB, CMake. Также я использую API Level 26, и минимальный SDK также равен 26 (OREO, 8.0).

Я создал native_lib.cpp и создал несколько файлов для тестирования FD.

Я сделал простой маленький класс для тестирования.

Класс имеет int FileDescriptor, char* buffer.

Я проверил переменные, и, похоже, все прошло успешно. ASharedMemory_Create() returns fd, и я могу получить размер памяти из ASharedMemory_getSize(int fd).

Но как я могу получить доступ к общей памяти из другого процесса? Мне нужно использовать Java для IPC? Если я могу, я хочу использовать только родной. В настоящее время Java только для пользовательского интерфейса.

https://developer.android.com/ndk/reference/group/memory

Я чечекд здесь. Если есть что-то, на что я могу сослаться, пожалуйста, дайте мне знать. Спасибо.

Edited ------------------------------------------- --------

Я хочу сделать разделяемую память как родительской, так и дочерней. Также хотите получить доступ к общей памяти свободно. Ребенок к ребенку, ребенок к родителям, родители к ребенку.

Создание дескриптора файла и буфера у родителей работает гладко, но когда я пытаюсь сделать буфер или fd у потомка, я не могу получить к нему доступ.

Я использовал то же имя и размер для ASharedMemory_create, но, на мой взгляд, другой процесс создал другой дескриптор файла. Не знаю, что не так.

Ниже мой native_lib.cpp для тестирования. Функции соответствуют кнопкам, кроме Init. Init называется onCreate.

int fd[4];
char* buffer[4];

int myFd;
int* cBuf;

const char* names[4] = {"Test", "Inter", "Process", "Mech"};
const int size = 512;

extern "C" JNIEXPORT void JNICALL
Java_org_techtwon_multipro_MainActivity_SyncBuffer(
        JNIEnv *env,
        jobject /* this */) {
    int cVal;
    memcpy(&cVal, cBuf, sizeof(int));

    for(int i = 0 ; i < cVal; ++i)
    {
        if(fd[i] != NULL) {
            buffer[i] = (char *) mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd[i], 0);
        }
    }
}

extern "C" JNIEXPORT void JNICALL
Java_org_techtwon_multipro_MainActivity_MakeFileDesc(
        JNIEnv *env,
        jobject /* this */) {

    pid_t pid = fork();
    int cVal;

    if(pid < 0) {
        return;
    } else if(pid == 0) {
        memcpy(&cVal, cBuf, sizeof(int));

        fd[cVal] = ASharedMemory_create(names[cVal], size);
        buffer[cVal] = (char*) mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd[cVal], 0);

        memset(buffer[cVal], 0, size);
        memcpy(buffer[cVal], names[cVal], strlen(names[cVal]));

        cVal++;
        memcpy(cBuf, &cVal, sizeof(int));

        sleep(1);
        exit(1);
    }
}

extern "C" JNIEXPORT void JNICALL
Java_org_techtwon_multipro_MainActivity_Init(
        JNIEnv *env,
        jobject /* this */) {
    myFd = ASharedMemory_create("Num", sizeof(int));
    cBuf = (int*) mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, myFd, 0);

    for(int i = 0 ; i < 4; ++i) fd[i] = ASharedMemory_create(names[i], size);

    buffer[0] = (char*) mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd[0], 0);
    memcpy(buffer[0], names[0], strlen(names[0]));

    memset(cBuf, 0, sizeof(int));
}

extern "C" JNIEXPORT jint JNICALL
Java_org_techtwon_multipro_MainActivity_GetFd(
        JNIEnv *env,
        jobject /* this */, jint idx) {
    return fd[idx];
}

extern "C" JNIEXPORT jbyteArray JNICALL
Java_org_techtwon_multipro_MainActivity_GetBuffer(
        JNIEnv *env,
        jobject /* this */, jint idx) {

    jbyteArray tmp = (*env).NewByteArray(strlen(buffer[idx]));

    env->SetByteArrayRegion(tmp, 0, strlen(buffer[idx]), (jbyte*) buffer[idx]);

    return tmp;
}

extern "C" JNIEXPORT jint JNICALL
Java_org_techtwon_multipro_MainActivity_GetcVal(
        JNIEnv *env,
        jobject /* this */, jint idx) {

    int cVal;
    memcpy(&cVal, cBuf, sizeof(int));

    return cVal;
}

1 Ответ

0 голосов
/ 30 октября 2018

Фрагмент кода в официальных документах имеет довольно четкое представление:

int fd = ASharedMemory_create("memory", 128);

// By default it has PROT_READ | PROT_WRITE | PROT_EXEC.
char *buffer = (char *) mmap(NULL, 128, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

strcpy(buffer, "This is an example."); // trivially initialize content

// limit access to read only
ASharedMemory_setProt(fd, PROT_READ);

// share fd with another process here and the other process can only map with PROT_READ.

На самом деле вам не нужно передавать fd другому процессу; вы можете получить доступ к той же общей памяти, вызвав ASharedMemory_create("memory", 128) из другого процесса. Имя и Имя не имеет значения, полезно только для отладки. Размер должен совпадать.

Обратите внимание, что этот API довольно новый, он недоступен для Nougat и ниже, но вы можете работать с общей памятью, используя тот же /dev/ashmem с ранних версий Android:

#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/ashmem.h>

int fd = open("/dev/ashmem", O_RDWR);

ioctl(fd, ASHMEM_SET_NAME, "memory");
ioctl(fd, ASHMEM_SET_SIZE, 128);

char *buffer = (char * ) mmap(NULL, 128, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

Существует даже хороший пример упаковки этой общей памяти для использования в Java: ANDROID - СОЗДАНИЕ ОБЩЕЙ ПАМЯТИ С ИСПОЛЬЗОВАНИЕМ ASHMEM .

...