我已將一個結構數組從 C#(托管代碼)傳遞到 C(非托管代碼)。結構的內存在 C# 端分配。該數組以 C 代碼填充。我的代碼是多線程的。數組的填充由一個線程完成,另一個線程從結構數組中讀取已填充的項。但是我無法從第二個線程讀取數據,直到第一個線程退出,但是內存由兩個線程共享。示例代碼C# 結構public struct Data{ public IntPtr str; [MarshalAs(UnmanagedType.I4)] public int id;}在 C# 端分配結構數組的內存GCHandle[] handles = new GCHandle[10];for (int i = 0; i < 10; i++){ _data[i] = new Data(); byte[] bd = new byte[100]; handles[i] = GCHandle.Alloc(bd, GCHandleType.Pinned); data[i].str = handles[i].AddrOfPinnedObject();}第一個線程將此結構數組_data傳遞給非托管代碼(C 代碼)以使用 func 進行填充void func([In,Out] Data[] _data);第二個線程開始讀取填充的結構數據,但第一個線程仍在填充靜態索引的數據。在這種情況下,數據可用于但顯示0,但在C端它顯示正確的填充值,即5。請幫助為什么結構成員int id的數據為0。正確的值僅在第一個線程結束后出現。但是,由于內存是共享的,因此,一旦被非托管代碼填充,它必須立即可用。_data[0].str_data[0].id任何幫助將不勝感激。我希望即使線程 1 沒有結束,線程 2 也必須能夠獲取已在非托管代碼中填充的索引值。
1 回答

神不在的星期二
TA貢獻1963條經驗 獲得超6個贊
由于將托管數組傳遞給非托管代碼,因此 clr 會先將該數組復制到另一個內存塊中,然后將其傳遞給非托管函數。非托管函數完成后,clr 會將內存封送回托管數組,然后得到結果。
解決方案是將數組地址直接與不安全代碼一起使用。
extern void func(Data* data);
fixed(Data* p = _data)
{
func(p);
}
如果您不喜歡不安全的代碼,由于結構數組的內存是順序的,因此您可以傳遞第一個元素的引用。但我不確定這是否足夠安全。
extern void func(ref Data data);
func(ref _data[0]);
- 1 回答
- 0 關注
- 151 瀏覽
添加回答
舉報
0/150
提交
取消