C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[2]: Blittableとなる構造体の定義について


(過去ログ 107 を表示中)

[トピック内 3 記事 (1 - 3 表示)]  << 0 >>

■63779 / inTopicNo.1)  Blittableとなる構造体の定義について
  
□投稿者/ Unripe01 (13回)-(2012/10/09(Tue) 22:04:32)

分類:[C#] 

いつもお世話になっております。

マーシャリングについて勉強中です。

.NET Framework 4.0上でなのですが、

http://msdn.microsoft.com/ja-jp/library/75dwhxf7(VS.80).aspx

に記載されている複合型のBlittable構造体(System.Valuetypeの派生型)を作成しているつもりなのですが
実際に構造体を作成し、GCHandle.AllocでPinned指定したところ
「オブジェクトに、プリミティブでないか、または blittable でないデータが含まれています。」例外が発生します。

以下の内容より下記ソースコードはBlittableのつもりなのですが、違うのでしょうか?

<引用>
次の複合型も blittable 型です。
整数の配列など、blittable 型の 1 次元配列。ただし、blittable 型の可変配列を含む型自体は blittable ではありません。
blittable 型だけを含む、書式指定された値型 (それらが書式指定された型としてマーシャリングされる場合)。


◆構造体宣言部分 byte配列を持つ構造体。サイズ固定させているので可変ではないと理解。
	[StructLayout( LayoutKind.Sequential )]
	public struct BlittableIntStruct
	{
		public short sht;
		[MarshalAs( UnmanagedType.ByValArray, SizeConst = 20000 )]
		public byte[] Array1;
		[MarshalAs( UnmanagedType.ByValArray, SizeConst = 20000 )]
		public byte[] Array2;
		[MarshalAs( UnmanagedType.ByValArray, SizeConst = 20000 )]
		public byte[] Array3;
	}

◆例外発生箇所のコード

[DllImport( "FooFuncsDll.dll", EntryPoint="BlittableInt" )]
private extern static int BlittableIntPointer( IntPtr* pointer );

BlittableIntStruct testStrct = new BlittableIntStruct();
GCHandle targetGCHandle = GCHandle.Alloc( testStrct , GCHandleType.Pinned );←ここでNG

◆アンマネージ側のコード

long MyFooFuncs::BlittableInt( SampleStruct_Blittable * pStruct )

		// サンプル構造体(Blittableのつもり)
		typedef struct {
			unsigned short	shortChar;//(2b)
			unsigned char byteArray1[20000];//(20000b)
			unsigned char byteArray2[20000];//(20000b)
			unsigned char byteArray3[20000];//(20000b)
		} SampleStruct_Blittable;


最終的に検証し、知り得たいことは
マネージヒープを直接参照するような(マーシャリングなしで)ポインタを取得し、
操作することでオブジェクトの内容を変更出来る手段はないか探しております。

レガシーなAPI呼び出しにおいてマーシャリングが発生する場合においては、
レガシーコードに近いパフォーマンスを得ることは難しいのでしょうか?






引用返信 編集キー/
■63780 / inTopicNo.2)  Re[1]: Blittableとなる構造体の定義について
□投稿者/ Hongliang (2回)-(2012/10/09(Tue) 23:56:53)
この文脈における固定配列は、fixedキーワードを使った固定サイズバッファを指すはずです。

> 最終的に検証し、知り得たいことは
> マネージヒープを直接参照するような(マーシャリングなしで)ポインタを取得し、
> 操作することでオブジェクトの内容を変更出来る手段はないか探しております。

例えばunsafeコンテキストにおけるfixedでの固定などがありますが、なんのために内容を変更したいのか分からないことには何とも。

> レガシーなAPI呼び出しにおいてマーシャリングが発生する場合においては、
> レガシーコードに近いパフォーマンスを得ることは難しいのでしょうか?

レガシーっていうと違和感。
どういう想定において近いパフォーマンスというのかよく判りません。
取り敢えず、managed/unmanagedのコンテキスト切り替えコストは相当な大きさなので、小さい処理を多く呼び出すのはパフォーマンス的には好ましくないですね。

// 結局マネージで処理したいのかアンマネージで処理したいのかどっちなんだろ…。
引用返信 編集キー/
■63782 / inTopicNo.3)  Re[2]: Blittableとなる構造体の定義について
□投稿者/ Unripe01 (14回)-(2012/10/10(Wed) 13:13:41)
Hongliang さん

回答ありがとうございます。

> この文脈における固定配列は、fixedキーワードを使った固定サイズバッファを指すはずです。

なるほど!!!「固定配列」という文言がどこにもなかったので
fixedをするという概念がありませんでした。
試しに同じようなサイズをもたせた構造体を用意し、
マーシャリング指定と固定配列の動作を確認してみました。

◆構造体宣言
[StructLayout( LayoutKind.Sequential )]
public struct BlittableIntStructMemCopy
{
public fixed byte Array1[20000];
public fixed byte Array2[20000];
public fixed byte Array3[20000];
}

[StructLayout( LayoutKind.Sequential )]
public struct BlittableIntStruct
{
[MarshalAs( UnmanagedType.ByValArray, SizeConst = 20000 )]
public byte[] Array1;
[MarshalAs( UnmanagedType.ByValArray, SizeConst = 20000 )]
public byte[] Array2;
[MarshalAs( UnmanagedType.ByValArray, SizeConst = 20000 )]
public byte[] Array3;
}

◆呼び出し
[DllImport( "FooFuncsDll.dll", EntryPoint="BlittableInt" )]
public extern static int BlittableInt( [In] ref BlittableIntStruct objStruct );
[DllImport( "FooFuncsDll.dll", EntryPoint="BlittableInt" )]
private extern static int BlittableIntPointer( ref BlittableIntStructMemCopy pointer );

※どちらも[In]属性のみ
DLL呼び出しを5000回ループさせる。

◆DLLの中身(C++)
構造体に適当な値を放り込むだけ

◆結果
5000回実行の経過時間
 マーシャリングありの方は
  0.0471秒 (1件当り0.00942ミリ秒)
 fixedキーワードの構造体
  0.0107秒 (1件当り0.00214ミリ秒)

かつ、マーシャリングありの方は構造体がnullのままで、
fixedはメモリコピーが発生していると考えられ、
構造体の内容が書き換わっていました。


> レガシーっていうと違和感。
> どういう想定において近いパフォーマンスというのかよく判りません。

すみません、VB6からC++で実装されたDLLを呼び出した時の時間と、C#で呼び出した時の経過時間が
あまりにも違うので疑問に思っておりました。(C++の関数の実装は、構造体のポインタを渡す)
VB6は単純に構造体を VarPtr(objStruct)として渡していて、
C#の方はref渡しすればポインタの参照か値渡しになると解釈していたのですが
マーシャリングやメモリ固定の挙動を調べていくうちに、どういった事ができるのか?
という疑問が発生していました。

> // 結局マネージで処理したいのかアンマネージで処理したいのかどっちなんだろ…。

今回質問させていただいたのは、どちらでも・・・なんです。
ただ例えば、byte配列を操作する時、「速度のみ」を追い求めた時にやっぱり
低級言語には勝てないのかなと。。。思いました。

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -