首页 文章

在CUDA DLL上的C#P / Invoke最终导致AccessViolationException

提问于
浏览
2

这真让我抓狂 . 我看了一遍,但我不确定我究竟究竟是什么导致了这个错误 .

我正在调用一个DLL(我编写为一个单独的项目),它在我正在使用的一些数据上运行CUDA内核 . 虽然,我怀疑这个问题不是由CUDA造成的,因为代码已经过测试并至少运行一次,通常是64到100次,然后才会导致AccessViolationException .

问题是,我传递了三个公共静态数组:

public static float[] neuronInputs;
public static float[] connectionOutputs;
public static int[] calcOrder;

来自neuronInputs的数据被复制到GPU上,然后被操作,然后被复制回connectionOutputs(只读取calcOrder,但不写入) . 我使用connectionOutputs数组执行一系列操作 . 然后我写下了neuronInputs数组,并将其发送回GPU . 重复直到失败 . 它总是失败 .

我正在调用这个函数:

[DllImport("CUDANeural.dll")] 
 static extern void GenerateSubstrateConnections(
 [In, Out]    [MarshalAs(UnmanagedType.LPArray)]  float[] neuronInputs,
 [In, Out] [MarshalAs(UnmanagedType.LPArray)] int[] calcOrder,
 [In, Out]      [MarshalAs(UnmanagedType.LPArray)] float[] outWeights
    );

我只为三个数组分配一次内存,并为每个数组分配一个大块 . 我已经在托管端测试了它,并且我无法在CUDA代码中的数组之外进行索引 .

我想我的问题是,是什么导致了这个AccessViolationException?假设它不是CUDA代码 .

编辑:这是来自非管理方面的电话

extern "C" __declspec(dllexport) void GenerateSubstrateConnections( float* neuronInputs, int* calcOrder, float* outWeights);

看起来我对编程的CUDA方面可能是错的 . 我在对GenerateSubstrateConnections的调用结束时添加了一个cudaExitThread()调用,这似乎纠正了这个问题 . 但是,为了澄清,我称之为不同的功能:

[DllImport("CUDANeural.dll")]
static extern void DebugSubstrateConnections(
[In, Out]     IntPtr neuronInputs,
[In, Out]  IntPtr calcOrder,
[In, Out]      IntPtr outWeights
);

在我在托管代码中调用GenerateSubstrateConnections之前,我将GCHandles固定

SubstrateDescription.inputHandle = GCHandle.Alloc(SubstrateDescription.neuronInputs, GCHandleType.Pinned);
 SubstrateDescription.connectionHandle = GCHandle.Alloc(SubstrateDescription.outputConnections, GCHandleType.Pinned);
calcHandle = GCHandle.Alloc(calcOrder, GCHandleType.Pinned);

然后打电话

GenerateSubstrateConnections(
SubstrateDescription.inputHandle.AddrOfPinnedObject(), 
calcHandle.AddrOfPinnedObject(),
SubstrateDescription.connectionHandle.AddrOfPinnedObject());

我不完全确定这是否有必要,但我知道它有效(目前) . 感谢您的所有评论,他们帮助我解决了这个问题 .

2 回答

  • 1

    也许是线程安全问题 . 由于您使用的是静态内存,因此您应该锁定对象,或使用其他一些同步选项,除非您完全确定它是单线程的 .

  • 1

    我不确定你是否可以在CUDA函数上做一个简单的pInvoke,因为它们没有在主处理器上运行 . 直接使用本机CUDA API的最佳选择可能是使用C / CLI . nVidia刚刚发布了支持包 . 其他更简单的选项包括使用OPENCL,它具有名为OpenTK的.Net库,它为大多数用途提供托管包装 .

相关问题