C\#+unsafe 가 없 는 비 위탁 관리 대수 그룹 예제 상세 설명(large unmanaged array in c\#without'unsafe'keyword)

C\#큰 배열 을 신청 합 니 다(Use a large array in C\#)
C\#에서 가끔 은 큰 배열 을 신청 하고 사용 한 다음 에 사용 하 는 메모리 가 필요 합 니 다.
Sometimes I need to allocate a large array, use it and then release its memory space immediately.
C\#에서 제공 하 는 int[]array=new int[1000000];이러한 배열 의 메모리 방출 은 프로그래머 가 완전히 제어 하기 어렵 고 큰 배열 을 신청 한 후에 프로그램 이 느 려 질 수 있 습 니 다.
If I use something like  int[] array = new int[1000000]; , it will be difficult to release its memory space by programmer and the app probably runs slower and slower.
특히 C\#+OpenGL 프로 그래 밍 에서 저 는 VAO/VBO 를 사용 할 때 위탁 관리 되 지 않 은 배열 을 설계 해 야 합 니 다.예 를 들 어 glBufferData 를 사용 할 때 아래 의 glBufferData 를 사용 하고 싶 습 니 다.
Specially in C#+OpenGL routines when I'm using VAO/VBO, I need an unmanaged array for glBufferData:

/// <summary>
 ///     VBO   。
 /// </summary>
 /// <param name="target"></param>
 /// <param name="data"></param>
 /// <param name="usage"></param>
 public static void glBufferData(uint target, UnmanagedArrayBase data, uint usage)
 {
 GetDelegateFor<glBufferData>()((uint)target,
 data.ByteLength, //        
 data.Header, //        
 (uint)usage);
 }
 // ...
 // glBufferData   
 private delegate void glBufferData(uint target, int size, IntPtr data, uint usage);
VBO 의 데 이 터 를 지정 할 때 float,vec 3 등 유형 일 수 있 습 니 다.
And the content in VBO can be float, vec3 and any other structs.

/// <summary>
 ///     posotion array.
 /// </summary>
 static vec3[] positions = new vec3[]
 {
 new vec3(0.0f, 1.0f, 0.0f),
 new vec3(-1.0f, -1.0f, 1.0f),
 // ...
 new vec3(-1.0f, -1.0f, 1.0f),
 };
// Create a vertex buffer for the vertex data.
 {
 uint[] ids = new uint[1];
 GL.GenBuffers(1, ids);
 GL.BindBuffer(GL.GL_ARRAY_BUFFER, ids[0]);
 //   vec3             
 UnmanagedArray<vec3> positionArray = new UnmanagedArray<vec3>(positions.Length);
 for (int i = 0; i < positions.Length; i++)
 {
  //   this[i]                  
  positionArray[i] = positions[i];
 }
 GL.BufferData(BufferDataTarget.ArrayBuffer, positionArray, BufferDataUsage.StaticDraw);
 GL.VertexAttribPointer(positionLocation, 3, GL.GL_FLOAT, false, 0, IntPtr.Zero);
 GL.EnableVertexAttribArray(positionLocation);
 }
UnmanagedArray
그래서 저 는 이러한 위탁 관리 가 아 닌 배열 유형 을 설 계 했 습 니 다.unsafe 가 없 으 면 모든 struct 유형 을 일반적인 매개 변수 로 받 아들 일 수 있 고 수시로 메모 리 를 방출 할 수 있 습 니 다.
So I designed this UnmangedArray : no 'unsafe' keyword, takes any struct as generic parameter, can be released anytime you want.

1 /// <summary>
 2 ///      sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, decimal, bool   struct      。
 3 /// <para>    enum    T。</para>
 4 /// </summary>
 5 /// <typeparam name="T">sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, decimal, bool   struct,     enum    T。</typeparam>
 6 public class UnmanagedArray<T> : UnmanagedArrayBase where T : struct
 7 {
 8 
 9 /// <summary>
 10 ///     sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, decimal, bool   struct      。 
 11 /// </summary>
 12 /// <param name="count"></param>
 13 [MethodImpl(MethodImplOptions.Synchronized)]
 14 public UnmanagedArray(int count)
 15 : base(count, Marshal.SizeOf(typeof(T)))
 16 {
 17 }
 18 
 19 /// <summary>
 20 ///         <paramref name="index"/>   。
 21 /// </summary>
 22 /// <param name="index"></param>
 23 /// <returns></returns>
 24 public T this[int index]
 25 {
 26 get
 27 {
 28  if (index < 0 || index >= this.Count)
 29  throw new IndexOutOfRangeException("index of UnmanagedArray is out of range");
 30 
 31  var pItem = this.Header + (index * elementSize);
 32  //var obj = Marshal.PtrToStructure(pItem, typeof(T));
 33  //T result = (T)obj;
 34  T result = Marshal.PtrToStructure<T>(pItem);// works in .net 4.5.1
 35  return result;
 36 }
 37 set
 38 {
 39  if (index < 0 || index >= this.Count)
 40  throw new IndexOutOfRangeException("index of UnmanagedArray is out of range");
 41  
 42  var pItem = this.Header + (index * elementSize);
 43  //Marshal.StructureToPtr(value, pItem, true);
 44  Marshal.StructureToPtr<T>(value, pItem, true);// works in .net 4.5.1
 45 }
 46 }
 47 
 48 /// <summary>
 49 ///              。
 50 /// </summary>
 51 /// <returns></returns>
 52 public IEnumerable<T> GetElements()
 53 {
 54 if (!this.disposed)
 55 {
 56  for (int i = 0; i < this.Count; i++)
 57  {
 58  yield return this[i];
 59  }
 60 }
 61 }
 62 }
 63 
 64 /// <summary>
 65 ///         。
 66 /// </summary>
 67 public abstract class UnmanagedArrayBase : IDisposable
 68 {
 69 
 70 /// <summary>
 71 ///     。
 72 /// </summary>
 73 public IntPtr Header { get; private set; }
 74 
 75 /// <summary>
 76 ///     。
 77 /// </summary>
 78 public int Count { get; private set; }
 79 
 80 /// <summary>
 81 ///         。
 82 /// </summary>
 83 protected int elementSize;
 84 
 85 /// <summary>
 86 ///        。(     *         )。
 87 /// </summary>
 88 public int ByteLength
 89 {
 90 get { return this.Count * this.elementSize; }
 91 }
 92 
 93 
 94 /// <summary>
 95 ///      。
 96 /// </summary>
 97 /// <param name="elementCount">    。</param>
 98 /// <param name="elementSize">        。</param>
 99 [MethodImpl(MethodImplOptions.Synchronized)]
100 protected UnmanagedArrayBase(int elementCount, int elementSize)
101 {
102 this.Count = elementCount;
103 this.elementSize = elementSize;
104 
105 int memSize = elementCount * elementSize;
106 this.Header = Marshal.AllocHGlobal(memSize);
107 
108 allocatedArrays.Add(this);
109 }
110 
111 private static readonly List<IDisposable> allocatedArrays = new List<IDisposable>();
112 
113 /// <summary>
114 ///       <see cref="UnmanagedArray"/>。
115 /// </summary>
116 [MethodImpl(MethodImplOptions.Synchronized)]
117 public static void FreeAll()
118 {
119 foreach (var item in allocatedArrays)
120 {
121  item.Dispose();
122 }
123 allocatedArrays.Clear();
124 }
125 
126 ~UnmanagedArrayBase()
127 {
128 Dispose();
129 }
130 
131 #region IDisposable Members
132 
133 /// <summary>
134 /// Internal variable which checks if Dispose has already been called
135 /// </summary>
136 protected Boolean disposed;
137 
138 /// <summary>
139 /// Releases unmanaged and - optionally - managed resources
140 /// </summary>
141 /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
142 protected void Dispose(Boolean disposing)
143 {
144 if (disposed)
145 {
146  return;
147 }
148 
149 if (disposing)
150 {
151  //Managed cleanup code here, while managed refs still valid
152 }
153 //Unmanaged cleanup code here
154 IntPtr ptr = this.Header;
155 
156 if (ptr != IntPtr.Zero)
157 {
158  this.Count = 0;
159  this.Header = IntPtr.Zero;
160  Marshal.FreeHGlobal(ptr);
161 }
162 
163 disposed = true;
164 }
165 
166 /// <summary>
167 /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
168 /// </summary>
169 public void Dispose()
170 {
171 this.Dispose(true);
172 GC.SuppressFinalize(this);
173 }
174 
175 #endregion
176  
177 }

UnmanagedArray
사용 방법(사용 방법)
UnmanagedArray는 일반적인 배열 처럼 사용 방식 이 간단 합 니 다.
Using UnamangedAray is just like a normal array(int[], vec3[], etc.):

internal static void TypicalScene()
 {
 const int count = 100;

 //   float  
 var floatArray = new UnmanagedArray<float>(count);
 for (int i = 0; i < count; i++)
 {
 floatArray[i] = i;
 }
 for (int i = 0; i < count; i++)
 {
 var item = floatArray[i];
 if (item != i)
 { throw new Exception(); }
 }

 //   int  
 var intArray = new UnmanagedArray<int>(count);
 for (int i = 0; i < count; i++)
 {
 intArray[i] = i;
 }
 for (int i = 0; i < count; i++)
 {
 var item = intArray[i];
 if (item != i)
 { throw new Exception(); }
 }

 //   bool  
 var boolArray = new UnmanagedArray<bool>(count);
 for (int i = 0; i < count; i++)
 {
 boolArray[i] = i % 2 == 0;
 }
 for (int i = 0; i < count; i++)
 {
 var item = boolArray[i];
 if (item != (i % 2 == 0))
 { throw new Exception(); }
 }

 //   vec3  
 var vec3Array = new UnmanagedArray<vec3>(count);
 for (int i = 0; i < count; i++)
 {
 vec3Array[i] = new vec3(i * 3 + 0, i * 3 + 1, i * 3 + 2);
 }
 for (int i = 0; i < count; i++)
 {
 var item = vec3Array[i];
 var old = new vec3(i * 3 + 0, i * 3 + 1, i * 3 + 2);
 if (item.x != old.x || item.y != old.y || item.z != old.z)
 { throw new Exception(); }
 }

 //   foreach
 foreach (var item in vec3Array.GetElements())
 {
 Console.WriteLine(item);
 }

 //           ,         vec3Array 。
 vec3Array.Dispose();

 //                 ,                 。
 UnmanagedArrayBase.FreeAll();
 }
읽 기 및 쓰기 UnmanagedArray
UnmanagedArrayHelper
UnmanagedArray를 신청 하고 사용 해 야 할 때 가 많 기 때문에 this[index]색인 방식 을 직접 사용 하면 속도 가 느 릴 수 있 습 니 다.그래서 저 는 몇 가지 보조 방법 을 추가 하여 UnmanagedArray를 빨리 읽 고 쓰 는 문 제 를 해결 합 니 다.

public static class UnmanagedArrayHelper
 {
 ///// <summary>
 /////    1         (“T”)      ,           
 ///// </summary>
 ///// <typeparam name="T"></typeparam>
 ///// <param name="array"></param>
 ///// <returns></returns>
 //public static unsafe T* FirstElement<T>(this UnmanagedArray<T> array) where T : struct
 //{
 // var header = (void*)array.Header;
 // return (T*)header;
 //}

 /// <summary>
 ///                 。
 /// </summary>
 /// <param name="array"></param>
 /// <returns></returns>
 public static unsafe void* FirstElement(this UnmanagedArrayBase array)
 {
 var header = (void*)array.Header;

 return header;
 }

 public static unsafe void* LastElement(this UnmanagedArrayBase array)
 {
 var last = (void*)(array.Header + (array.ByteLength - array.ByteLength / array.Length));

 return last;
 }

 /// <summary>
 ///                            。
 /// </summary>
 /// <param name="array"></param>
 /// <returns></returns>
 public static unsafe void* TailAddress(this UnmanagedArrayBase array)
 {
 var tail = (void*)(array.Header + array.ByteLength);

 return tail;
 }
 }
어떻게 사용 합 니까?
이 유형 은 3 개의 확장 방법 을 실 현 했 습 니 다.UnmanagedArray의 첫 번 째 요소 의 위치,마지막 요소 의 위치,마지막 요소+1 의 위 치 를 얻 을 수 있 습 니 다.이런 unsafe 방법 으로 C 언어 와 같은 읽 기와 쓰기 속 도 를 실현 할 수 있다.
다음은 하나의 예 다.unsafe 방식 으로 UnmanagedArray를 읽 고 쓰 면 this[index]방식 보다 10~70 배 빠 릅 니 다.

public static void TypicalScene()
 {
 int length = 1000000;
 UnmanagedArray<int> array = new UnmanagedArray<int>(length);
 UnmanagedArray<int> array2 = new UnmanagedArray<int>(length);

 long tick = DateTime.Now.Ticks;
 for (int i = 0; i < length; i++)
 {
 array[i] = i;
 }
 long totalTicks = DateTime.Now.Ticks - tick;

 tick = DateTime.Now.Ticks;
 unsafe
 {
 int* header = (int*)array2.FirstElement();
 int* last = (int*)array2.LastElement();
 int* tailAddress = (int*)array2.TailAddress();
 int value = 0;
 for (int* ptr = header; ptr <= last/*or: ptr < tailAddress*/; ptr++)
 {
  *ptr = value++;
 }
 }
 long totalTicks2 = DateTime.Now.Ticks - tick;
 Console.WriteLine("ticks: {0}, {1}", totalTicks, totalTicks2);// unsafe method works faster.

 for (int i = 0; i < length; i++)
 {
 if (array[i] != i)
 {
  Console.WriteLine("something wrong here");
 }
 if (array2[i] != i)
 {
  Console.WriteLine("something wrong here");
 }
 }

 array.Dispose();
 array2.Dispose();
 }

unsafe
 {
  vec3* header = (vec3*)vec3Array.FirstElement();
  vec3* last = (vec3*)vec3Array.LastElement();
  vec3* tailAddress = (vec3*)vec3Array.TailAddress();
  int i = 0;
  for (vec3* ptr = header; ptr <= last/*or: ptr < tailAddress*/; ptr++)
  {
  *ptr = new vec3(i * 3 + 0, i * 3 + 1, i * 3 + 2);
  i++;
  }
  i = 0;
  for (vec3* ptr = header; ptr <= last/*or: ptr < tailAddress*/; ptr++, i++)
  {
  var item = *ptr;
  var old = new vec3(i * 3 + 0, i * 3 + 1, i * 3 + 2);
  if (item.x != old.x || item.y != old.y || item.z != old.z)
  { throw new Exception(); }
  }
 }
2015-08-25
StructLayout 와 Marshalas 로 복잡 한 struct 를 지원 합 니 다.
OpenGL 에서 UnmanagedArray를 사용 해 야 합 니 다.그 중에서 mat4 정 의 는 다음 과 같 습 니 다.

1 /// <summary>
 2 /// Represents a 4x4 matrix.
 3 /// </summary>
 4 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Size = 4 * 4 * 4)]
 5 public struct mat4
 6 {
 7 /// <summary>
 8 /// Gets or sets the <see cref="vec4"/> column at the specified index.
 9 /// </summary>
10 /// <value>
11 /// The <see cref="vec4"/> column.
12 /// </value>
13 /// <param name="column">The column index.</param>
14 /// <returns>The column at index <paramref name="column"/>.</returns>
15 public vec4 this[int column]
16 {
17 get { return cols[column]; }
18 set { cols[column] = value; }
19 }
20 
21 /// <summary>
22 /// Gets or sets the element at <paramref name="column"/> and <paramref name="row"/>.
23 /// </summary>
24 /// <value>
25 /// The element at <paramref name="column"/> and <paramref name="row"/>.
26 /// </value>
27 /// <param name="column">The column index.</param>
28 /// <param name="row">The row index.</param>
29 /// <returns>
30 /// The element at <paramref name="column"/> and <paramref name="row"/>.
31 /// </returns>
32 public float this[int column, int row]
33 {
34 get { return cols[column][row]; }
35 set { cols[column][row] = value; }
36 }
37 
38 /// <summary>
39 /// The columms of the matrix.
40 /// </summary>
41 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
42 private vec4[] cols;
43 }
44 
45 /// <summary>
46 /// Represents a four dimensional vector.
47 /// </summary>
48 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Size = 4 * 4)]
49 public struct vec4
50 {
51 public float x;
52 public float y;
53 public float z;
54 public float w;
55 
56 public float this[int index]
57 {
58 get
59 {
60  if (index == 0) return x;
61  else if (index == 1) return y;
62  else if (index == 2) return z;
63  else if (index == 3) return w;
64  else throw new Exception("Out of range.");
65 }
66 set
67 {
68  if (index == 0) x = value;
69  else if (index == 1) y = value;
70  else if (index == 2) z = value;
71  else if (index == 3) w = value;
72  else throw new Exception("Out of range.");
73 }
74 }
75 }

mat4
메모:UnmanagedArray가 지원 하 는 struct,T 의 크기 는 확인 되 어야 합 니 다.그래서 mat 4 에서 우 리 는[StructLayout(LayoutKind.Sequential,Charset=Charset.Ansi,Size=4*4*4)]로 mat 4 의 크기 를 4 개의 vec 4*4 개의 float*4 개의 바이트(각각 float)=64 바이트 로 지정 하고 private vec 4[]cols;[Marshalas(Unmanaged Type.by ValArray,SizeConst=4)]로 cols 의 요소 수 를 4 로 규정 하 였 습 니 다.이후 vec 4 에 있 는[StructLayout(LayoutKind.Sequential,Charset=Charset.Ansi,Size=4*4)]는 쓰 지 않 아 도 됩 니 다.vec 4 는 간단 한 float 필드 가 4 개 밖 에 없 기 때문에 복잡 한 유형 이 포함 되 어 있 지 않 습 니 다.
다음은 테스트 용례 다.

mat4 matrix = glm.scale(mat4.identity(), new vec3(2, 3, 4));

 var size = Marshal.SizeOf(typeof(mat4));
 size = Marshal.SizeOf(matrix);

 UnmanagedArray<mat4> array = new UnmanagedArray<mat4>(1);
 array[0] = matrix;

 mat4 newMatirx = array[0]; // newMatrix should be equal to matrix

 array.Dispose();
matrix 와 new Matrix 가 같다 면 상기 Attribute 설정 이 정확 하 다 는 것 을 설명 합 니 다.
총결산
C\#+unsafe 가 없 는 비 위탁 관리 대수 그룹(large unmanaged array in c\#without'unsafe'keyword)에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 C\#unsafe 가 없 는 비 위탁 관리 대수 그룹 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 문장 을 계속 찾 아 보 세 요.앞으로 많은 응원 바 랍 니 다!

좋은 웹페이지 즐겨찾기