从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的见解。

非常感谢。

从C#调用C++线程

您不能为此使用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);
        }
    }