从 C# 调用 C++ 线程
Posted
技术标签:
【中文标题】从 C# 调用 C++ 线程【英文标题】:Calling C++ thread from C# 【发布时间】:2014-11-05 13:37:25 【问题描述】:我对 C++ 比较陌生。出于某种原因,我需要做一个流动模型的工作。
第 1 步:我在 C++ 中有一个 Method1
,它将更改从 C# 传递的变量的值。我称该变量为str
。
第 2 步:创建一个线程并在几毫秒后将 str
更改为另一个值。
在 C++ 中:
char* temp; // Temporary pointer
void Thread1(void* arr)
Sleep(1000); // Wait for one second
strcpy_s(temp, 100, "Thread 1"); // Change value of str to ‘Thread 1’ -> A exception was threw because ‘temp’ is undefined
__declspec(dllexport) void Method1(char* str)
temp = str; // Keep pointer of ‘str’ to temporary pointer to change ‘str’ value in Thread
strcpy_s(temp, 100, "Method 1"); // Change ‘str’ to ‘Method 1’. -> It work OK
_beginthread(Thread1, 0, NULL); // Start Thread1
在 C# 中:
public static StringBuilder str = new StringBuilder(100);
[DllImport("C++.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void Method1(StringBuilder test);
static void Main(string[] args)
Method1(str); // Call Method1 in C++ dll.
Console.WriteLine(str.ToString()); // Result: “Method 1” -> OK
while (true)
Console.WriteLine(str.ToString()); // Print str value every 0.1 second. It exception after 1 second
Thread.Sleep(100);
调用Method1
时的结果,str
变为Method1
,但Thread1
运行时:指针temp
为空,所以抛出异常。
请提供一些关于如何在Thread1
中更改str
的见解。
非常感谢。
【问题讨论】:
【参考方案1】:您不能为此使用StringBuilder
。这是因为封送处理假定对象仅在函数执行期间使用(即假定函数返回后,本机代码将不再使用它)。 C++ 不知道 StringBuilder
是什么,因此运行时仅在 P/Invoke 调用期间通过缓冲区提供对它的访问。
您应该分配一些内存并将其传递给您的函数。这是一种应该有效的方法:
[DllImport("C++.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void Method1(byte* test);
然后:
unsafe
var buffer = new byte[100]; // a C++ char is 1 byte
fixed (byte* ptr = buffer)
Method1(ptr);
while (true)
// WARNING: There's no locking here (see comment below)
// It may cause undefined behavior.
var str = Encoding.ASCII.GetString(buffer);
Console.WriteLine(str);
Thread.Sleep(100);
缓冲区必须在 C++ 代码可以访问它的整个过程中保持固定 (fixed
)。
请注意,这仍然不安全:
没有锁,因此 C# 代码读取字符串的同时可能与 C++ 代码写入字符串的时间相同。这可能会导致未定义的行为。 您的缓冲区必须至少为 100 字节(因为提供给strcpy_s
的值)。这是隐含的。最好将缓冲区大小传递给您的函数。
【讨论】:
【参考方案2】:您不应将字符串复制到未分配的指针。实际上,当您使用指针时,这只是一个地址(4 个字节),因此您没有足够的空间来复制您的字符串。
将 char *temp 更改为 char temp[100]。
这样你就要求内存给你 100 字节来复制数据。
这应该可以工作
【讨论】:
【参考方案3】:变量 temp 只是一个指针,你的赋值 temp = str;仅将指针分配给字符串指针。要点是您永远不会为 temp 分配内存。 考虑到这一点,在调用线程后 str 参数超出范围并被取消分配,因此您的临时指针现在无效。
【讨论】:
【参考方案4】:感谢所有回答。 最后,我基于 Lucas Trzesniewski 的 解决方案和我的代码工作。 我将 C# 代码更改为:
[DllImport("C++.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void Method1(byte[] str);
static void Main(string[] args)
var buffer = new byte[100]; // a C++ char is 1 byte
Method1(buffer);
while (true)
var str = Encoding.ASCII.GetString(buffer);
Console.WriteLine(str);
Thread.Sleep(100);
【讨论】:
以上是关于从 C# 调用 C++ 线程的主要内容,如果未能解决你的问题,请参考以下文章