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

时间:2010-09-10 17:19:17

标签: c# pinvoke cuda dllimport access-violation

这让我发疯了。我看了一遍,但我不确定我究竟究竟是什么导致了这个错误。

我正在调用一个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 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

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