2014-11-05 91 views
1

我對C++比較陌生。出於某種原因,我需要做一個流動模型的工作。從C調用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的信息。

非常感謝。

回答

0

您不應將字符串複製到未分配的指針。事實上,當你使用一個指針時,這只是一個地址(4個字節),所以你沒有足夠的空間來複制你的字符串。

將char * temp更改爲char temp [100]。

有了這個,你可以讓內存給你100個字節來複制數據。

這應該工作

0

變量temp只是一個指針,而你的賦值temp = str;只將指針分配給字符串指針。要點是你永遠不會爲temp分配內存。 考慮到這一點,在調用線程之後,str參數超出範圍,並被取消分配,因此您的臨時指針現在無效。

2

對此,您不能使用StringBuilder。這是因爲編組假定對象將只在函數執行過程中使用(即它假定函數返回後本地代碼將不再使用它)。 C++不知道什麼是StringBuilder,因此運行時只會在P/Invoke調用期間通過緩衝區提供對它的訪問。

你應該分配一些內存並將它傳遞給你的函數。這裏有一個方式,也應該工作:在整個期間的C++代碼可以訪問它

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); 
     } 
    } 
} 

緩衝區必須保持固定(fixed):

[DllImport("C++.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern void Method1(byte* test); 

然後。

注意,這仍是不安全的:

  • 沒有鎖,所以C#代碼可能讀在同一時間比C++代碼寫入到它的字符串。這可能導致未定義的行爲。
  • 您的緩衝區必須至少有100個字節(因爲提供的值爲strcpy_s)。這是隱含的。將緩衝區大小傳遞給你的函數會更好。
0

感謝您的所有答案。 最後,我基於盧卡斯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); 
     } 
    }