Zen*_* Qu 5 c# xcode interop memory-management unity-game-engine
我有一个C#脚本,通过System.Runtime.Interop调用C函数.我设法调用了C函数,但是在管理C和C#之间的缓冲区时遇到了问题.
在我的情况下,C是(数据)生产者,C#是消费者.
我的问题是当我在C#中读取数据时,有时我得到正确的值但有时我得到NULL.
这个问题已经解决了.我正在粘贴错误的方法,并在此与我分享正确的方法.
C#代码是一个统一脚本(Mono开发的一部分),C代码在Xcode中,这意味着我不能在我的C代码中使用.Net框架函数.
这是我的C代码(写入缓冲区并从缓冲区读取):
static char InteropBF[INTEROP_BUFFER_SIZE];
static int mutex = 0;
// for the c code to put its message in buffer
void PutToBuffer(char* name, char* content)
{
while (mutex>0);
mutex++;
strcat(InteropBF, name);
strcat(InteropBF, ",");
strcat(InteropBF, content);
strcat(InteropBF, ",");
printf("Interop Buffer: %s\n", InteropBF);
mutex--;
}
// for the C# code to poll and read from C
void* ReadFromBuffer(void* temp)
{
while (mutex>0);
mutex++;
strcpy(temp, InteropBF);
// memcpy(temp, InteropBF, INTEROP_BUFFER_SIZE);
strcpy(InteropBF, "");
mutex--;
return temp;
}
Run Code Online (Sandbox Code Playgroud)
我将函数ReadFromBuffer()暴露给C#:
[DllImport ("CCNxPlugin")]
public static extern IntPtr ReadFromBuffer(IntPtr temp);
Run Code Online (Sandbox Code Playgroud)
然后,我调用这个函数:
IntPtr temp = Marshal.AllocCoTaskMem(8912);
CCN.ReadFromBuffer(temp);
string news = Marshal.PtrToStringAuto(temp);
if(news != "")
{
print (news);
}
Marshal.FreeCoTaskMem(temp);
Run Code Online (Sandbox Code Playgroud)
使用此代码我有时会获得正确的缓冲区内容,但更常见的是我从Marshal.PtrToStringAuto函数中获取NULL.
我想粘贴我在这里找到的工作代码和参考资料 -
C功能:
struct bufnode
{
char* name;
char* content;
struct bufnode *next;
};
struct bufnode* bufhead = NULL;
struct bufnode* buftail = NULL;
// for the c code to put its message in buffer
void PutToBuffer(char* name, char* content)
{
struct bufnode *temp = malloc(sizeof(struct bufnode));
temp->name = malloc(256);
temp->content = malloc(256);
strcpy(temp->name,name);
strcpy(temp->content,content);
temp->next = NULL;
if (bufhead == NULL && buftail == NULL) {
bufhead = temp;
buftail = temp;
}
else if(bufhead != NULL && buftail != NULL){
buftail->next = temp;
buftail = temp;
}
else {
printf("Put to buffer error.\n");
}
}
// for the C# code to poll and read from C
struct bufnode* ReadFromBuffer()
{
if (bufhead != NULL && buftail != NULL) {
// temp->name = bufhead->name;
// temp->content = bufhead->content;
// temp->next = NULL;
struct bufnode* temp = bufhead;
if (bufhead == buftail) {
bufhead = NULL;
buftail = NULL;
}
else {
bufhead = bufhead->next;
}
return temp;
}
else if(bufhead == NULL && buftail == NULL)
{
return NULL;
}
else {
return NULL;
}
}
Run Code Online (Sandbox Code Playgroud)
C#包装器:
[StructLayout (LayoutKind.Sequential)]
public struct bufnode
{
public string name;
public string content;
public IntPtr next;
}
[DllImport ("CCNxPlugin")]
public static extern IntPtr ReadFromBuffer();
Run Code Online (Sandbox Code Playgroud)
在C#中调用函数:
CCN.bufnode BufNode;
BufNode.name = "";
BufNode.content = "";
BufNode.next = IntPtr.Zero;
IntPtr temp = CCN.ReadFromBuffer();
if(temp != IntPtr.Zero)
{
BufNode = (CCN.bufnode)Marshal.PtrToStructure(temp, typeof(CCN.bufnode));
print(BufNode.name);
print(BufNode.content);
Marshal.FreeCoTaskMem(temp);
}
Run Code Online (Sandbox Code Playgroud)
您正在传回一个堆栈变量。该变量可以在从方法返回时在 C/C++ 中“收集”或释放——这将在到达 PtrToStringAuto 时随机导致内存损坏。这可以解释为什么它有时为空。您需要分配传回 C# 代码的内存,并且该代码需要释放内存(或者 C/C++ 需要以某种方式执行此操作)。
您可以在 c/c++ 中使用 CoTaskMemAlloc 执行此操作,在 C# 中使用 Marshal.FreeCoTaskMem 释放它。