使用 Android NDK SharedMemory.h 进行多进程
Multiprocess by Using Android NDK SharedMemory.h
我一直在 Android Studio(使用 NDK)中尝试多处理(使用共享内存)。我安装了 NDK、LLDB、CMake。我还使用 API 级别 26,最小 SDK 也是 26(OREO,8.0)。
我创建了 native_lib.cpp,并制作了一些用于测试 FD 的文件。
我制作了简单的小class用于测试。
Class 有 int FileDescriptor, char* buffer.
我检查了变量,似乎已经成功了。 ASharedMemory_Create() returns fd
,我可以从 ASharedMemory_getSize(int fd)
获取内存大小。
但是我怎样才能从另一个进程访问共享内存呢?我需要为 IPC 使用 java 吗?如果可以的话,我只想使用本机。目前 java 仅适用于 UI。
https://developer.android.com/ndk/reference/group/memory
我查到了这里。如果有值得我参考的东西,请告诉我。谢谢你。
已编辑------------------------------------ --------------
我想在 parent 和 child 中创建共享内存。也想自由访问共享内存。 Child 到 child,child 到 parents,parents 到 child。
在 parents 中创建文件描述符和缓冲区工作顺利,但是当我尝试在 child 中创建缓冲区或 fd 时,我无法访问它。
我为 ASharedMemory_create
使用了相同的名称和大小,但我认为其他进程生成不同的文件描述符。不知道怎么了。
下面是我的native_lib.cpp
测试。除了 Init
之外,与 Buttons 匹配的功能。 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;
}
official docs 中的代码片段非常清楚:
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.
name没有任何意义,只对调试有帮助。 尺寸应该匹配。
这就是API你 for API 29 and higher, the old ways (below) don't work anymore.
如果您还需要涵盖 API 26 以下的设备,您需要一个 fallback 将 IOCTL 直接指向 /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 – CREATING SHARED MEMORY USING ASHMEM.
我一直在 Android Studio(使用 NDK)中尝试多处理(使用共享内存)。我安装了 NDK、LLDB、CMake。我还使用 API 级别 26,最小 SDK 也是 26(OREO,8.0)。
我创建了 native_lib.cpp,并制作了一些用于测试 FD 的文件。
我制作了简单的小class用于测试。
Class 有 int FileDescriptor, char* buffer.
我检查了变量,似乎已经成功了。 ASharedMemory_Create() returns fd
,我可以从 ASharedMemory_getSize(int fd)
获取内存大小。
但是我怎样才能从另一个进程访问共享内存呢?我需要为 IPC 使用 java 吗?如果可以的话,我只想使用本机。目前 java 仅适用于 UI。
https://developer.android.com/ndk/reference/group/memory
我查到了这里。如果有值得我参考的东西,请告诉我。谢谢你。
已编辑------------------------------------ --------------
我想在 parent 和 child 中创建共享内存。也想自由访问共享内存。 Child 到 child,child 到 parents,parents 到 child。
在 parents 中创建文件描述符和缓冲区工作顺利,但是当我尝试在 child 中创建缓冲区或 fd 时,我无法访问它。
我为 ASharedMemory_create
使用了相同的名称和大小,但我认为其他进程生成不同的文件描述符。不知道怎么了。
下面是我的native_lib.cpp
测试。除了 Init
之外,与 Buttons 匹配的功能。 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;
}
official docs 中的代码片段非常清楚:
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.
name没有任何意义,只对调试有帮助。 尺寸应该匹配。
这就是API你
如果您还需要涵盖 API 26 以下的设备,您需要一个 fallback 将 IOCTL 直接指向 /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 – CREATING SHARED MEMORY USING ASHMEM.