共有メモリアクセス及び構造体定義について、マッピングされる位置がおかしい問題と、AccessViolationExceptionがthrowされる問題がそれぞれ発生しており、それを解消したく思っています。
質問の背景
C側で以下の構造体を共有メモリにマッピングしています:
C
1struct Data 2{ 3 uint32_t member1; 4 uint32_t member2; 5 uint32_t member3[128]; 6};
共有メモリアクセスでは(MemoryMappedFile及びMemoryMappedViewAccessorを使わず)WIN32 APIのOpenFileMapping()及びMapViewOfFile()を用いてIntPtrを得て行っています。
問題ない動作
Spanを使う場合は、期待通りのデータを参照できています。
C#
1void Hoge(IntPtr addr) 2{ 3 Span<uint> span; 4 unsafe 5 { 6 span = new Span<uint>(addr.ToPointer(), 130); 7 } 8 // ここでspan変数を使ってアクセス 9 // →例外はthrowされないし、共有メモリ上の値が正しく取得できる。 10}
なので、共有メモリ上のデータ、及びIntPtrが指すアドレス位置は問題ないことがわかっています。
発生した問題(1) マッピングされる位置がおかしい
C#側で以下の構造体を定義してアクセスしようとしました:
C#
1[StructLayout(LayoutKind.Sequential, Pack = 1)] 2public struct Data 3{ 4 public uint member1; 5 public uint member2; 6 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] 7 public uint[] member3; 8}; 9 10void Hoge(IntPtr addr) 11{ 12 unsafe 13 { 14 ref var data = ref Unsafe.AsRef<Data>(attr.ToPointer()); 15 // ここでdata.member1にアクセス 16 // →先頭から12bytesの位置(C側構造体でのmember3[1])の値が読める 17 } 18}
そうすると、上記コード中のコメントに記述したとおり、member1にアクセスしようとしているのにmember3[1]にアクセスされてしまいます。
発生した問題(2) AccessViolationExceptionがthrowされる
上記(1)でアクセス位置がおかしいので、Dataの定義を以下のように修正しました:
C#
1[StructLayout(LayoutKind.Explicit)] 2public struct Data 3{ 4 [FieldOffset(0)] 5 public uint member1; 6 [FieldOffset(4)] 7 public uint member2; 8 [FieldOffset(8)] 9 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] 10 public uint[] member3; 11};
そうすると、member1及びmember2は共有メモリ上の値を正しく取得できたのですが、member3[0]の値を取得しようとするとAccessViolationExceptionがthrowされました。
質問
- 問題(1)においてアクセス位置がずれてしまうのは何故なのでしょうか。
- 問題(2)においてmember3にアクセスできないのは何故なのでしょうか。
- どのように修正したら、共有メモリ上のデータに直接アクセスできるでしょうか。ここでいう「直接アクセス」とは、スタック上に別途Dataの構造体をnewして、共有メモリからその変数にmemcpy()するようなことを避けたい、という意味です。これは次の2つの理由によります:(1)パフォーマンス上の懸念(2)共有メモリ上のデータのset/getにおいて毎回Write/Readを呼ぶような実装上の煩雑性を避けたい。
開発・動作環境
Windows 10 Pro 1909 (Build 18363.1139)
Visual Studio Professional 2019 ver.16.7.y
C# コンソールアプリケーション
ターゲットフレームワーク .NET Framework 4.8
「32ビットを選ぶ」のチェックをオフ
「アンセーフコードの許可」にチェック
System.Memory 4.5.4をNugetで取得して利用
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/11/04 23:03