ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

从C#传递到C代码的结构数组

2019-12-11 05:08:00  阅读:203  来源: 互联网

标签:unmanaged marshalling c


我已经将结构数组从C#(托管代码)传递到C(非托管代码). struct的内存分配在C#端.该数组用C代码填充.我的代码是多线程的.数组的填充由一个线程完成,另一个线程从struct数组中读取已填充的项目.但是我无法从第二个线程读取数据,直到第一个线程退出,但是两者共享内存.

样例代码

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);

第二个线程开始读取已填充的结构数据,但第一个线程仍在填充数据以进行剩余索引.在这种情况下,数据可用于
_data [0] .str
 但
_data [0] .id
 显示0,但在C端显示正确的填充值,即5.请帮助为什么struct成员int id的数据将变为0.正确的值仅在第一个线程结束之后出现.但是,由于内存是共享的,因此一旦被非托管代码填充,它必须立即可用.

任何帮助将不胜感激.

我希望即使线程1没有结束,线程2也必须能够获取已经在非托管代码中填充的索引值.

解决方法:

因为您将托管数组传递给非托管代码,所以clr将首先将该数组复制到另一个内存块中,然后将其传递给非托管函数.非托管函数完成后,clr将把内存封送回托管数组,然后得到结果.

一种解决方案是直接将数组地址与不安全的代码一起使用.

extern void func(Data* data);

fixed(Data* p = _data)
{
    func(p);
}

如果您不喜欢不安全的代码,由于结构数组的存储是顺序的,因此可以传递第一个元素的引用.但是我不确定这是否足够安全.

extern void func(ref Data data);

func(ref _data[0]);

标签:unmanaged,marshalling,c
来源: https://codeday.me/bug/20191211/2106551.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有