Использование C DLL в C#
От: igsilya  
Дата: 14.10.11 11:47
Оценка:
Здравствуйте.
Мне нужно использовать библиотеку liblinear в моей программе на C#. Я экспортировал её в dll. функции вроде вызываются, но программа падает от ошибок работы с памятью, а именно, скорее всего потому, что происходят ошибки при её освобождении или она вообще не освобождается.

то что было

struct feature_node
{
    int index;
    double value;
};

struct problem
{
    int l, n;
    int *y;
    struct feature_node **x;
    double bias;            /* < 0 if no bias term */  
};

enum { L2R_LR, L2R_L2LOSS_SVC_DUAL, L2R_L2LOSS_SVC, L2R_L1LOSS_SVC_DUAL, MCSVM_CS, L1R_L2LOSS_SVC, L1R_LR, L2R_LR_DUAL }; /* solver_type */

struct parameter
{
    int solver_type;

    /* these are for training only */
    double eps;            /* stopping criteria */
    double C;
    int nr_weight;
    int *weight_label;
    double* weight;
};

struct model
{
    struct parameter param;
    int nr_class;        /* number of classes */
    int nr_feature;
    double *w;
    int *label;        /* label of each class */
    double bias;
};

__declspec(dllexport) struct model* train(const struct problem *prob, const struct parameter *param);
__declspec(dllexport) void cross_validation(const struct problem *prob, const struct parameter *param, int nr_fold, int *target);

__declspec(dllexport) int predict_values(const struct model *model_, const struct feature_node *x, double* dec_values);
__declspec(dllexport) int predict(const struct model *model_, const struct feature_node *x);
__declspec(dllexport) int predict_probability(const struct model *model_, const struct feature_node *x, double* prob_estimates);

__declspec(dllexport) int save_model(const char *model_file_name, const struct model *model_);
__declspec(dllexport) int save_model_and_clean(char *model_file_name, struct model *model_,parameter* param);

__declspec(dllexport) struct model *load_model(const char *model_file_name);

__declspec(dllexport) int get_nr_feature(const struct model *model_);
__declspec(dllexport) int get_nr_class(const struct model *model_);
__declspec(dllexport) void get_labels(const struct model *model_, int* label);

__declspec(dllexport) void free_model_content(struct model *model_ptr);
__declspec(dllexport) void free_and_destroy_model(struct model **model_ptr_ptr);
__declspec(dllexport) void destroy_param(struct parameter *param);

__declspec(dllexport) const char *check_parameter(const struct problem *prob, const struct parameter *param);
__declspec(dllexport) int check_probability_model(const struct model *model);
__declspec(dllexport) void set_print_string_function(void (*print_func) (const char*));



это как я объявил функции в C# программе

    unsafe struct LiBlinear
    {

        public struct feature_node
        {
            public int index;
            public double value;
        };

        public struct problem
        {
            public int l, n;
            public int* y;
            public feature_node** x;
            public double bias;            /* < 0 if no bias term */
        };

        public struct parameter
        {
            public int solver_type;

            /* these are for training only */
            public double eps;            /* stopping criteria */
            public double C;
            public int nr_weight;
            public int* weight_label;
            public double* weight;
        };

        public struct model
        {
            public parameter param;
            public int nr_class;        /* number of classes */
            public int nr_feature;
            public double* w;
            public int* label;        /* label of each class */
            public double bias;
        };

        public enum ENUM_ { L2R_LR, L2R_L2LOSS_SVC_DUAL, L2R_L2LOSS_SVC, L2R_L1LOSS_SVC_DUAL, MCSVM_CS, L1R_L2LOSS_SVC, L1R_LR, L2R_LR_DUAL }; /* solver_type */

        

        [DllImport("LIBlinearDLL.dll", EntryPoint = "train")]
        public static extern model* train( problem* prob, parameter* param);
        [DllImport("LIBlinearDLL.dll")]
        public static extern int predict_values(model* model_, feature_node* x, double* dec_values);
        [DllImport("LIBlinearDLL.dll")]
        public static extern int predict(model* model_, feature_node* x);
        [DllImport("LIBlinearDLL.dll")]
        public static extern int save_model(byte* model_file_name, model* model_);
        [DllImport("LIBlinearDLL.dll")]
        public static extern int save_model_and_clean(byte* model_file_name, model* model_, parameter* param);
        [DllImport("LIBlinearDLL.dll")]
        public static extern model* load_model(char* model_file_name);
        [DllImport("LIBlinearDLL.dll")]
        public static extern int get_nr_feature(model* model_);
        [DllImport("LIBlinearDLL.dll")]
        public static extern void free_and_destroy_model(model** model_ptr_ptr);
        [DllImport("LIBlinearDLL.dll")]
        public static extern void destroy_param(parameter* param);
    }



собственно использование

                const int NUM_FEATURES = 2000;
                LiBlinear.problem prob = new LiBlinear.problem();
                prob.l = selection.Count; // number of instances
                prob.bias = -1; // bias feature
                prob.n = NUM_FEATURES; // number of features + one for bias if needed

                prob.y = (int*)Marshal.AllocCoTaskMem(prob.l); // allocate space for labels
                prob.x = (LiBlinear.feature_node**)Marshal.AllocCoTaskMem(prob.l); // allocate space for features

                for (int i = 0; i < prob.l; i++)
                {
                    prob.x[i] = (LiBlinear.feature_node*)Marshal.AllocCoTaskMem(sizeof(LiBlinear.feature_node) * (NUM_FEATURES + 2));
                    prob.x[i][NUM_FEATURES].index = -1;  // -1 marks the end of list
                    for (int j = 0; j < NUM_FEATURES; j++)
                    {
                        prob.x[i][j].index = 1 + j; // 1-based feature number
                        prob.x[i][j].value = selection[i][j];
                    }
                    prob.y[i] = labels[i];
                    selection[i].Clear();
                }

                selection.Clear();
                
                LiBlinear.parameter param = new LiBlinear.parameter();
                param.solver_type = (int)LiBlinear.ENUM_.L2R_L2LOSS_SVC_DUAL;
                param.C = 1;
                param.eps = 1e-4;
                param.nr_weight = 0;
                param.weight_label = null;
                param.weight = null;

                LiBlinear.model* model = LiBlinear.train(&prob, &param);
                
                byte[] save_model_file_name=new byte[]{bla bla bla};
                byte* save_name = (byte*)Marshal.AllocCoTaskMem(save_model_file_name.Length);
                for (int i = 0; i < save_model_file_name.Length; i++)
                    save_name[i] = save_model_file_name[i];
                
                LiBlinear.save_model_and_clean(save_name, model, &param);
                
                Marshal.FreeCoTaskMem((IntPtr)save_name);

                Marshal.FreeCoTaskMem((IntPtr)prob.y);
                for (int i = 0; i < prob.l; i++) Marshal.FreeCoTaskMem((IntPtr)prob.x[i]);
                Marshal.FreeCoTaskMem((IntPtr)prob.x);


если объем памяти используемой не очень велик, то иногда работает нормально, но умирает при повторных вызовах.
буду признателен за конструктивные предложения.

весь проект здесь
c# .net c dll
Re: Использование C DLL в C#
От: Аноним  
Дата: 08.03.12 13:10
Оценка:
Здравствуйте!

Вот отличная статья о том, как интегрировать Native(C++) код в C# проект. Надеюсь она вам поможет:
http://itw66.ru/blog/c_sharp/499.html
dll c#
Re: Использование C DLL в C#
От: ecconaut  
Дата: 11.04.12 07:29
Оценка:
Может быть причина в использовании методов выделения памяти для взаимодействия с COM-объектами: Marshal.AllocCoTaskMem и Marshal.FreeCoTaskMem?
Кажется для выделения неуправляемой памяти в общем случае служат методы Marshal.AllocHGlobal и Marshal.FreeHGlobal, разве нет?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.