3

以下に対応する最善の方法は何ですか。

独自のバックエンドと通信するためにネイティブ C dll とやり取りする、リアルタイムでパフォーマンスが重要なアプリケーション。

ネイティブ API には、何百もの構造体、ネストされた構造体、およびこれらの構造体を介してデータをやり取りするメソッドがあります。

ロジックに c# を使用したいので、cli とマーシャリングを優先して安全でない c# を使用することにしました。私は方法を知っており、後でこれを実装したので、「use cli」と返信しないでください。数百の構造体を 1 秒間に 100 回マーシャリングすると、安全でない c# を調査するのに十分な遅延が発生します。

ほとんどの c 構造体には数十のフィールドが含まれているため、それぞれの入力を最小限に抑える方法を探しています。この時点で、VS マクロを実行して、必要に応じて各行要素を C# の同等の設定配列に変換し、固定サイズにしました。これは、ネストされた構造体配列に到達するまではうまく機能します。たとえば、次の 2 つの構造体があります。

[StructLayout(LayoutKind.Sequential,Pack=1)]
unsafe struct User{
    int id;
    fixed char name[12];
}

[StructLayout(LayoutKind.Sequential,Pack=1)]
unsafe structs UserGroup{
    fixed char name[12];
    fixed User users[512]
    int somethingElse;
    fixed char anotherThing[16]
}

実行時に多くのことをする必要がないように、固定ユーザー [512] に対応する最善の方法は何ですか?

提案が行われる例を見てきました

[StructLayout(LayoutKind.Sequential,Pack=1)]
unsafe structs UserGroup{
    fixed char name[12];
    User users_1;
    User users_2;
    ...
    User users_511;
    int somethingElse;
    fixed char anotherThing[16]
}

別のアイデアは、 User のサイズをバイト単位で計算し、これを行うことです

[StructLayout(LayoutKind.Sequential,Pack=1)]
unsafe structs UserGroup{
    fixed char name[12];
    fixed byte Users[28*512];
    int somethingElse;
    fixed char anotherThing[16]
}

しかし、それは、この構造体を使用する必要があるたびに特別な処理を行うか、他のコードでラップする必要があることを意味します。このアプローチを避けたいAPIには十分なものがありますが、誰かがエレガントな方法を示すことができれば、それもうまくいきます

私が作成して例を出すことができないほど私を逃れている3番目のアプローチ(どこかで見たと思いますが、もう見つけられないと思います)は、ユーザーのサイズを指定するか、「固定」キーワードを使用できるように厳密なサイズにすることですその上で。

負荷がかかった状態で利用し、適切にスケーリングできる合理的なアプローチを推奨できる人はいますか?

4

1 に答える 1

1

安全でない構造体でネストされた構造体を見つける最善の方法は、それらを固定バイト配列として定義し、フィールドにランタイム変換プロパティを提供することです。例えば:

[StructLayout(LayoutKind.Sequential,Pack=1)]
unsafe struct UserGroup{
    fixed char name[12];
    fixed User users[512]
    int somethingElse;
    fixed char anotherThing[16]
}

になる:

[StructLayout(LayoutKind.Sequential,Pack=1)]
unsafe struct UserGroup{
    fixed char name[12];
    fixed byte users[512 * Constants.SizeOfUser]
    int somethingElse;
    fixed char anotherThing[16];
    public User[] Users
    {
        get
        {
            var retArr = new User[512];
            fixed(User* retArrRef = retArr){
                fixed(byte* usersFixed = users){
                    {
                        Memory.Copy(usersFixed, retArrRef,  512 * Constants.SizeOfUser);
                    }
                }
            }
            return retArr;
        }
    }
}

このコードは、ここで提供される Memory.Copy 関数を使用することに注意してください: http://msdn.microsoft.com/en-us/library/aa664786(v=vs.71).aspx

ゲッターの一般的な説明は次のとおりです。

  1. 戻り値にマネージド配列を割り当てる
  2. 安全でないポインターを取得して修正する
  3. 構造体のバイト配列への安全でないポインターを取得して修正する
  4. メモリを一方から他方にコピーする

管理された配列が構造体自体に格納されない理由は、そのレイアウトが変更され、正しく変換されなくなるためです。一方、管理されていないものから取得する場合、小道具は問題になりません。または、これを格納する別の管理対象オブジェクトにラップすることもできます。

于 2013-11-20T04:16:59.767 に答える