7

2 つの (ndk-) プロセス間でデータを共有したいと考えています。このために、このソースを使用してashmemを使用します。
1 つのプロセスが継続的に読み取り ( read_mem)、1 つのプロセスが 1 回書き込みを行っています ( 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


その他の情報

両方のファイルは、androidndk-buildコマンドを使用して実行可能ファイルとしてコンパイルされます
デバイス: LG Nexus 4 (AOSP Lollypop)存在すること
を確認/dev/ashmemしました。ここ
から撮影

4

1 に答える 1

29

Ashmem は Linux の通常の共有メモリのようには機能しませんが、これには十分な理由があります。

まず、「(deleted)」の部分を説明してみましょう。これは、ashmem がカーネルにどのように実装されているかの実装の詳細です。これが実際に意味することは、ファイル エントリが /dev/ashmem/ ディレクトリに作成され、後で削除されたが、少なくとも 1 つの開いているファイル記述子があるため、対応する i ノードがまだ存在していることです。

実際には、同じ名前の ashmem 領域をいくつか作成することができ、それらはすべて「/dev/ashmem/<name> (deleted)」として表示されますが、それぞれが異なる i ノードに対応するため、異なる メモリ 領域。/dev/ashmem/ の下を見ると、ディレクトリがまだ空であることがわかります。

そのため、ashmem 領域の名前は実際にはデバッグにのみ使用されます。既存のリージョンを名前で「開く」方法はありません。

ashmem i ノードと対応するメモリは、それに対する最後のファイル記述子が閉じられると、自動的に再利用されます。これは、クラッシュによってプロセスが停止した場合に、カーネルによってメモリが自動的に再利用されることを意味するため、便利です。これは、通常の SysV 共有メモリには当てはまりません (プロセスがクラッシュするとメモリがリークするだけです! Android のような組み込みシステムでは受け入れられないことです)。

テスト プログラムは、同じ名前の 2 つの異なる ashmem 領域を作成します。そのため、期待どおりに動作しません。代わりに必要なものは次のとおりです。

1) プロセスの 1 つに単一の ashmem 領域を作成します。

2) 新しいファイル記述子を最初のプロセスから 2 番目のプロセスへの領域に渡します。

これを行う 1 つの方法は、最初のプロセスを fork して 2 番目のプロセスを作成することです (これにより、ファイル記述子が自動的に複製されます) が、これは通常、Android ではお勧めできません。

より良い代替手段は、sendmsg() と recvmsg() を使用して、2 つのプロセス間で Unix ドメイン ソケットを介してファイル記述子を送信することです。これは一般的に注意が必要ですが、例として、NDK 用に作成された次のソース ファイルの SendFd() 関数と ReceiveFd() 関数を見てください。

https://android.googlesource.com/platform/ndk/+/android-5.0.0_r7/sources/android/crazy_linker/tests/test_util.h

出来上がり、これが役立つことを願っています

于 2015-01-08T22:35:12.760 に答える