通过p/invoke从C#使用XGBoost DLL [英] Use XGBoost DLL from c# via p/invoke
问题描述
我正在尝试使用 XGBoost的 dll(libxgboost.dll)创建DMatrix(就像一个2D数组),并获取它具有多少列.它可以正常运行,直到在下面的代码的int cols = ...
行中抛出System.AccessViolationException
为止:
I'm trying to use XGBoost's dll (libxgboost.dll) to create a DMatrix (which is like a 2D array) and get how many columns it has. It runs fine until it throws a System.AccessViolationException
at the int cols = ...
line in the code below:
using System;
using System.Runtime.InteropServices;
namespace basicXgboost
{
class Program
{
[DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)]
public static extern int XGDMatrixCreateFromFile([MarshalAs(UnmanagedType.LPStr)] string file, int silent, IntPtr outputPtr);
[DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)]
public static extern int XGDMatrixNumCol(IntPtr dmatrixPtr, IntPtr dmatrixColumnsPtr);
static void Main(string[] args)
{
IntPtr dmatrixPtr = Marshal.AllocHGlobal(1000000);
IntPtr dmatrixColumnsPtr = Marshal.AllocHGlobal(10);
int result = XGDMatrixCreateFromFile("../../libs/test.txt", 0, dmatrixPtr);
int cols = XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr);
Marshal.FreeHGlobal(dmatrixPtr);
Marshal.FreeHGlobal(dmatrixColumnsPtr);
}
}
}
为什么访问由XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr)
分配的非托管内存会导致System.AccessViolationException
?
Why does accessing unmanaged memory allocated with XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr)
cause a System.AccessViolationException
?
一种可能是我对这些功能使用的pinvoke错误.下面是我使用的每个dll函数的定义:
One possibility might be that I'm using pinvoke incorrectly for these functions. Below are the definitions for each dll function I use:
/*!
* \brief load a data matrix
* \param fname the name of the file
* \param silent whether print messages during loading
* \param out a loaded data matrix
* \return 0 when success, -1 when failure happens
*/
XGB_DLL int XGDMatrixCreateFromFile(const char *fname,
int silent,
DMatrixHandle *out);
/*!
* \brief get number of columns
* \param handle the handle to the DMatrix
* \param out The output of number of columns
* \return 0 when success, -1 when failure happens
*/
XGB_DLL int XGDMatrixNumCol(DMatrixHandle handle,
bst_ulong *out);
此处是我的项目的仓库.我正在使用Visual Studio Enterprise 2015.它在Windows 10 Pro(64位)上以调试"模式(针对x64)构建.可以在此处.尽管链接的存储库确实包含libxgboost.dll的副本.
Here is the repo for my project. I'm using Visual Studio Enterprise 2015 . It's built in "Debug" mode (targeting x64) on Windows 10 Pro (64-bit). x64 binaries for libxgboost.dll can be found here. Although the linked repo does contain a copy of libxgboost.dll.
推荐答案
尝试使用似乎由DLL使用的调用约定Cdecl.
Try to use the calling convention Cdecl which seems to be used by the DLL.
此外,XGDMatrixCreateFromFile
函数的签名是错误的.预期的参数不是指向您分配的某些内存的指针,但是该函数将自行分配内存,然后将指针作为输出参数返回.
Also, the signature of the XGDMatrixCreateFromFile
function is wrong. The parameter expected is not a pointer to some memory allocated by you, but the function will allocate memory itself and then return the pointer as an output parameter.
尝试以下代码.请注意在XGDMatrixCreateFromFile
函数的outputPtr
参数上使用out
关键字.
Try the following code. Note the use of the the out
keyword on the outputPtr
parameter in the XGDMatrixCreateFromFile
function.
[DllImport("C:\\dev\\libs\\xgboost\\build\\Release\\libxgboost.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int XGDMatrixCreateFromFile([MarshalAs(UnmanagedType.LPStr)] string file, int silent, out IntPtr outputPtr);
[DllImport("C:\\dev\\libs\\xgboost\\build\\Release\\libxgboost.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int XGDMatrixNumCol(IntPtr dmatrixPtr, IntPtr dmatrixColumnsPtr);
static void Main(string[] args)
{
IntPtr dmatrixPtr;
IntPtr dmatrixColumnsPtr = Marshal.AllocHGlobal(10);
int result = XGDMatrixCreateFromFile("C:\\dev\\libs\\xgboost\\demo\\data\\agaricus.txt.test", 0, out dmatrixPtr);
int cols = XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr);
Marshal.FreeHGlobal(dmatrixColumnsPtr);
}
此方法有效时,您还可以使用ulong
数据类型简化调用以获取列数:
When this works, you can then also simplify the call to get the number of columns by using the ulong
datatype:
[DllImport("C:\\dev\\libs\\xgboost\\build\\Release\\libxgboost.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int XGDMatrixCreateFromFile([MarshalAs(UnmanagedType.LPStr)] string file, int silent, out IntPtr outputPtr);
[DllImport("C:\\dev\\libs\\xgboost\\build\\Release\\libxgboost.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int XGDMatrixNumCol(IntPtr dmatrixPtr, out ulong dmatrixColumnsPtr);
static void Main(string[] args)
{
IntPtr dmatrixPtr;
ulong dmatrixColumns;
int result = XGDMatrixCreateFromFile("C:\\dev\\libs\\xgboost\\demo\\data\\agaricus.txt.test", 0, out dmatrixPtr);
int cols = XGDMatrixNumCol(dmatrixPtr, out dmatrixColumns);
}
这篇关于通过p/invoke从C#使用XGBoost DLL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!