Размещение вложенных небезопасных структур в C #

Каков наилучший способ размещения следующего:

Приложение, критически важное для производительности в режиме реального времени, которое взаимодействует с собственным Cll для связи с проприетарным бэкэндом.

В нативном API есть сотни и сотни структур, вложенных структур и методов, которые передают данные туда и обратно через эти структуры.

Хотите использовать c # для логики, поэтому остановились на небезопасном c # в пользу cli и marshaling. Я знаю, как и реализовал это через позже, поэтому, пожалуйста, не отвечайте «используйте cli». Маршалинг сотен структур сотню раз в секунду вносит достаточно существенную задержку, что оправдывает расследование небезопасного c #.

Большинство структур c содержит десятки полей, поэтому ищите метод, который бы выполнял минимальную типизацию для каждого из них. На этом этапе все сводится к запуску макроса VS для преобразования каждого строкового элемента в c # эквивалентные установочные массивы в фиксированный размер при необходимости. Это работает довольно хорошо, пока я не попал во вложенный массив struct. Так, например, у меня есть эти 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]
}

Другая идея заключалась в том, чтобы вычислить размер пользователя в байтах и ​​просто сделать это

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

Но это будет означать, что мне придется делать особую обработку для этой структуры каждый раз, когда мне понадобится ее использовать, или обернуть ее каким-нибудь другим кодом. В API достаточно тех, что я хотел бы избежать такого подхода, но если кто-то может продемонстрировать элегантный способ, которым я мог бы работать

Третий подход, который ускользает от меня настолько, что я не могу произвести и привести пример (я думаю, что где-то видел, но больше не могу его найти) — это указать размер для пользователя или каким-то образом сделать его строго определенным, чтобы вы могли использовать ключевое слово «fixed» в теме.

Кто-нибудь может порекомендовать разумный подход, который они использовали и хорошо масштабируется под нагрузкой?

2

Решение

Лучший способ найти вложенную структуру в небезопасных структурах — это определить их как фиксированные байтовые массивы, а затем предоставить свойство преобразования времени выполнения для поля. Например:

[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. скопировать память из одного в другой

Причина, по которой управляемый массив не сохраняется обратно в саму структуру, заключается в том, что он изменяет свою компоновку и больше не будет корректно переводиться, в то время как реквизит не представляет проблемы при получении его от неуправляемого. В качестве альтернативы это может быть включено в другой управляемый объект, который выполняет сохранение.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]