分享C#和C ++的变量 [英] Sharing variables between C# and C++

查看:142
本文介绍了分享C#和C ++的变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写在C#中的软件,该软件需要调用多次和许多线程函数在C ++非托管的DLL。

I'm writing a software in c# which needs to call many times and by many threads a function in a c++ unmanaged dll.

我有一个这样的C ++文件:

I have a C++ file like that:

// "variables" which consist in some simple variables (int, double) 
//  and in some complex variables (structs containing arrays of structs)


extern "C"
{
     __declspec(dllexport) int function1()
    {
        // some work depending on random and on the "variables"
    }
}

和C#类像

public class class1
{
    //  "variables" <--- the "same" as the C++ file's ones 
    //  Dll import <--- ok

    public void method1()
    {
        int [] result;

        for(int i=0; i<many_times; i++)
        {
            result = new int[number_of_parallel_tasks];                

            Parallel.For(0, number_of_parallel_tasks, delegate(int j)
            { 
                 // I would like to do  result[j] = function1()  
            });

            //  choose best result
            //  then update "variables" 
        }
    }

}

我写了我愿做......,因为C ++函数在每一轮需要有变数更新了。

I wrote "I would like to do ..." because the c++ function needs at each round to have the "variables" updated, too.

我的问题是:

是否有可能以避免每次路过参考C ++和C#之间共享内存?难道仅仅是浪费时间?

Is it possible to share memory between C++ and C# in order to avoid passing reference every time? Is it just a waste of time?

我读到内存映射文件。他们能帮助我吗?但是,你知道更合适的解决方案?结果
非常感谢你。

I read about memory mapped files. Could they help me? However, do you know more appropriate solutions?
Thank you very much.

推荐答案

有没有问题++使用P / Invoke,一旦你知道它是如何工作分享C#和C之间的内存。我建议阅读有关MSDN编组。您可能还需要阅读有关使用不安全的关键字和固定内存。

There is no problem sharing memory between C# and C++ using P/Invoke once you know how it works. I would suggest reading about marshaling in MSDN. You might also want to read about using the unsafe keyword and fixing memory.

下面是假定您的变量可以被描述为一个简单的结构示例:

Here is a sample that assumes that your variables can be described as a simple struct:

在C ++中声明你的功能如下:

In C++ declare your function as follows:

#pragma pack(1)
typedef struct VARIABLES
{
/*
Use simple variables, avoid pointers
If you need to use arrays use fixed size ones
*/
}variables_t;
#pragma pack()
extern "C"
{
     __declspec(dllexport) int function1(void * variables)
    {
        // some work depending on random and on the "variables"
    }
}

在C#中做这样的事情:

In C# do something like this:

[StructLayout(LayoutKind.Sequential, Pack=1)]
struct variables_t
{
/*
Place the exact same definition as in C++
remember that long long in c++ is long in c#
use MarshalAs for fixed size arrays
*/
};

[DllExport("YourDll.dll", CallingConvention=CallingConvention.Cdecl)]
static extern int function(ref variables_t variables); 

和在你的类:

variables_t variables = new variables_t();
//Initialize variables here
for(int i=0; i<many_times; i++)
{
    int[] result = new int[number_of_parallel_tasks];
    Parallel.For(0, number_of_parallel_tasks, delegate(int j)
    { 
          result[j] = function1(ref variables)  
    });

    //  choose best result
    //  then update "variables" 
}

您可以使用更复杂的场景,如分配和在C释放结构++,使用编组来获取数据回来就好建立自己的类读取和直接写入到非托管内存的其他形式。但是,如果你可以用一个简单的结构来保存你的变量上面的方法是最简单的。

You can use more complex scenarios like allocating and releasing the structure in c++, using other forms of marshaling to get the data back like building your own class to read and write directly to the unmanaged memory. But if you can use a simple struct to hold your variables the method above is the simplest.

编辑:如何正确处理更为复杂的数据指针

所以上面的示例是在我看来,正确的方法来共享数据C#和C ++之间,如果它是简单的数据,例如。持原始类型或基本类型的固定大小的数组结构。

So the sample above is in my opinion the correct way to "share" data between C# and C++ if it is simple data eg. a structure holding primitive types or arrays of fixed size of primitive types.

这是说其实有你可以使用C#访问内存的方式很少限制。欲了解更多信息,看看unsafe关键字,固定关键字和结构的GCHandle。仍然,如果您有包含其他结​​构等数组一个非常复杂的数据结构,那么你有一个更复杂的工作。

This being said there are actually very little limitations on the way you can access memory using C#. For more information look into the unsafe keyword, the fixed keyword and the GCHandle struct. And still if you have a very complex data structures that contain arrays of other structures etc. then you have a more complicated job.

在上述情况下,我建议就如何更新变量在C ++中移动的逻辑。
添加在C ++中的函数看起来是这样的:

In the case above I would recommend moving the logic on how to update the "variables" into C++. Add in C++ a function to look something like this:

extern "C"
{
     __declspec(dllexport) void updateVariables(int bestResult)
    {
        // update the variables
    }
}

我还是会建议不要让我提出以下方案中使用全局变量。
在C ++:

I would still suggest not to use global variables so I propose the following scheme. In C++:

typedef struct MYVERYCOMPLEXDATA
{
/*
Some very complex data structure
*/
}variables_t;
extern "C"
{
     __declspec(dllexport) variables_t * AllocVariables()
    {
        // Alloc the variables;
    }
     __declspec(dllexport) void ReleaseVariables(variables_t * variables)
    {
        // Free the variables;
    }
     __declspec(dllexport) int function1(variables_t const * variables)
    {
        // Do some work depending on variables;
    }
    __declspec(dllexport) void updateVariables(variables_t * variables, int bestResult)
    {
       // update the variables
    }
};

在C#中:

[DllExport("YourDll.dll", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr AllocVariables();
[DllExport("YourDll.dll", CallingConvention=CallingConvention.Cdecl)]
static extern void ReleaseVariables(IntPtr variables); 
[DllExport("YourDll.dll", CallingConvention=CallingConvention.Cdecl)]
static extern int function1(IntPtr variables); 
[DllExport("YourDll.dll", CallingConvention=CallingConvention.Cdecl)]
static extern void updateVariables(IntPtr variables, int bestResult); 

如果您仍然希望保持在C#的逻辑,你将不得不做类似如下:
创建一个类来保存从C ++返回的内存,写自己的内存访问逻辑。揭露使用拷贝语义数据为C#。我的意思是如下,
假设你有C ++这样的结构:

If you still want to maintain you logic in C# you will have to do something like the following: Create a class to hold the memory returned from C++ and write your own memory access logic. Expose the data to C# using copy semantics. What I mean is as follows, Say you have in C++ a structure like this:

#pragma pack(1)
typedef struct SUBSTRUCT
{
int subInt;
double subDouble;
}subvar_t;
typedef struct COMPLEXDATA
{
int int0;
double double0;
int subdata_length;
subvar_t * subdata;
}variables_t;
#pragma pack()

在C#中,你做这样的事情。

in C# you do something like this

[DllImport("kernel32.dll")]
static extern void CopyMemory(IntPtr dst, IntPtr src, uint size);

[StructLayout((LayoutKind.Sequential, Pack=1)]
struct variable_t
{    
    public int int0;
    public double double0;
    public int subdata_length;
    private IntPtr subdata;
    public SubData[] subdata
    {
        get
        {
             SubData[] ret = new SubData[subdata_length];
             GCHandle gcH = GCHandle.Alloc(ret, GCHandleType.Pinned);
             CopyMemory(gcH.AddrOfPinnedObject(), subdata, (uint)Marshal.SizeOf(typeof(SubData))*subdata_length);
             gcH.Free();
             return ret;
        }
        set
        {
             if(value == null || value.Length == 0)
             {
                 subdata_length = 0;
                 subdata = IntPtr.Zero;
             }else
             {
                 GCHandle gcH = GCHandle.Alloc(value, GCHandleType.Pinned);
                 subdata_length = value.Length;
                 if(subdata != IntPtr.Zero)
                     Marshal.FreeHGlobal(subdata);
                 subdata = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SubData))*subdata_length);
                 CopyMemory(subdata, gcH.AddrOfPinnedObject(),(uint)Marshal.SizeOf(typeof(SubData))*subdata_length);
                 gcH.Free();
             }
        }
    }
};
[StructLayout((LayoutKind.Sequential, Pack=1)]
sturct SubData
{
    public int subInt;
    public double subDouble;
};

在上述样品结构仍然可以作为第一样品中传递。当然,这仅仅是如何处理与结构的阵列内的结构araays和结构数组复杂的数据大纲。正如你可以看到你将需要大量复制到从内存损坏守护自己。此外,如果内存是通过C ++分配它将如果你使用FreeHGlobal释放它是非常糟糕的。
如果你想避免复制内存,仍然保持C#中的逻辑,你可以写与访问你想要比如什么都你将不得不直接设置方法或得到第N个数组成员的subInt本机内存包装 - 这种方式你一定要让你复制到您访问的是什么。

In the above sample the structure can still be passed as in the first sample. This of course is just an outline on how to handle complex data with araays of structures and arrays of structures within arrays of structures. As you can see you will need a lot of copying to guard yourself from memory corruption. Also if the memory is allocated via C++ it will be very bad if you use FreeHGlobal to free it. If you want to avoid copying memory and still maintain the logic within C# the you can write a native memory wrapper with accessors for what ever you want For instance you will have a method to directly set or get the subInt of Nth array member - This way you will keep your copies to exactly what you access.

另一种选择是编写特定的C ++函数做艰难数据为你办理,并根据您的逻辑从C#调用它们。

Another option would be to write specific C++ functions to do the difficult data handling for you and call them from C# according to your logic.

和最后但并非最不重要,你可以随时使用C ++与CLI界面。不过,我自己做的,只如果我必须 - 我不喜欢行话但对于非常复杂的数据,你肯定要考虑

And last but not least you can always use C++ with CLI interface. However I myself do it only if I must - I don't like the lingo but for very complex data you certainly have to consider it.

修改

我添加正确的调用约定到的DllImport的完整性。请注意,DllImport属性使用的默认调用约定是WINAPI(这在Windows上转化为__stdcall),而在C / C默认调用约定++(除非你改变了编译器选项)是__cdecl。

I added the correct calling convention to the DllImport for completeness. Please note that the default calling convention used by the DllImport attribute is Winapi (which on windows translates to __stdcall) while the default calling convention in C/C++ (unless you change the compiler options) is __cdecl.

这篇关于分享C#和C ++的变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆