3

What is the best way to accommodate the following:

Real time, performance critical application that interfaces with a native C dll for communicating with a proprietary back end.

The native api has hundreds upon hundreds of structs, nested structs and methods that pass data back and forth via these structs.

Want to use c# for logic, so decided on unsafe c# in favor of cli and marshaling. I know how and have implemented this via the later so please don't reply "use cli". Marshaling hundreds of structs a hundred times a second introduces a significant enough delay that it warranted investigating unsafe c#.

Most of the c structs contain dozens of fields, so looking for a method to do minimal typing on each. At this point, got it down to running a VS macro to convert each line element to c# equivalent setting arrays to fixed size when necessary. This work pretty well until I hit a nested struct array. So for example, I have these 2 structs:

[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]
}

What is the best way to accommodate fixed User users[512] so that to not have to do much during run time?

I have seen examples where the suggestion is to do

[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]
}

Another idea has been, to compute the size of User in bytes and just do this

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

But that would mean that I would have to do special treatment to this struct every time I need to use it, or wrap it with some other code. There are enough of those in the api that I would like to avoid this approach, but if someone can demonstrate an elegant way I that could work as well

A third approach that eludes me enough that I can't produce and example(i think i saw somewhere but cant find it anymore), is to specify size for User or somehow make it strictly sized so that you could use a "fixed" keyword on it.

Can anyone recommend a reasonable approach that they have utilized and scales well under load?

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

geter的一般解释如下:

  1. 为返回值分配一个托管数组
  2. 获取并修复指向它的不安全指针
  3. 获取并修复指向该结构的字节数组的不安全指针
  4. 将内存从一个复制到另一个

托管数组没有被存储回它自己的结构的原因是因为它会修改其布局并且不会再正确翻译,而从非托管获取它时道具是没有问题的。或者,这可以包装在另一个进行存储的托管对象中。

于 2013-11-20T04:16:59.767 回答