从C#调用C++线程
本文关键字:线程 C++ 调用 | 更新日期: 2023-09-27 18:29:24
我对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
为null,因此引发异常。请提供一些关于我如何在Thread1
中更改str
的见解。
非常感谢。
您不能为此使用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
的值)。这是隐含的。最好将缓冲区大小传递给您的函数
不应将字符串复制到未分配的指针。事实上,当您使用指针时,这只是一个地址(4字节),因此您没有足够的空间来复制字符串。
将char*temp更改为char-temp[100]。
这样,你就要求内存给你100字节来复制数据。
这应该工作
变量temp只是一个指针,您的赋值temp=str;只将指针分配给字符串指针。重点是,您永远不会为temp分配内存。考虑到这一点,在调用线程后,str参数超出范围并被取消分配,因此您的临时指针现在无效。
感谢您的回答。最后,我基于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);
}
}