通过PInvoke在单独的线程上调用C#回调

时间:2019-03-29 16:59:53

标签: c# multithreading lambda pinvoke

我试图通过PInvoke将回调从托管的C#程序整理到本地C ++ DLL。这些回调可能会在一个单独的线程上长时间延迟后被调用。我当前的设计发现,如果在本机层立即调用正确的数据,则可以正确调用回调,但是如果在单独的线程上延迟调用,则失败。这是设置的简单示例:

C#接口

public class Example
{
    private delegate void NativeLoginCallback(IntPtr bytes);

    [DllImport ("NativeExample")]
    private static extern void Example_loginAsync(NativeLoginCallback callback);

    private delegate void LoginCallback(string data);
    public void LoginAsync(LoginCallback callback)
    {
        NativeLoginCallback nativeCallback = (IntPtr bytes) =>
        {
            string data = MarshalUtility.Deserialize<string>(bytes);
            try
            {
                callback(data);
            }
            catch (Exception ex)
            {
                Debug.Log(ex);
            }
        }

        Example_loginAsync(nativeCallback);
    }
}

C接口

extern "C" __declspec(dllimport) void Example_loginAsync(void* callback)
{
    typedef void(*CSharpLoginCallbackType)(void* data);
    CSharpLoginCallbackType csharpCallback = (CSharpLoginCallbackType) callback;

    auto cppLoginCallback = [csharpCallback](std::string data)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(5000));

        unsigned char* dataBytes;
        MarshalUtility::Serialize(data, dataBytes);
        csharpCallback(dataBytes);
    };

    std::string testData = "This one is called immediately on same thread.";
    unsigned char* testDataBytes;
    MarshalUtility::Serialize(testData, testDataBytes);
    csharpCallback(testDataBytes);

    std::thread t(cppLoginCallback, "This one is called after 5 seconds on seperate thread.");
    t.detach();
}

C#呼叫者

public class ExampleIntegrator
{
    Example example = new Example();

    public void Test()
    {
        example.Login((string data) =>
        {
            Debug.Log(data);
        };
    }

};

我看到的输出是:

This one is called immediately on same thread.
NullReferenceException

我期望的输出是:

This one is called immediately on same thread.
This one is called after 5 seconds on seperate thread.

经检查,我发现在NativeLoginCallback范围内数据是正确的,即在行string data = MarshalUtility.Deserialize<string>(bytes);之后,调试器正确显示在单独的线程上5秒钟后调用了该代码。,但是发现回调是NullReference。如何确保回调不会为空?

0 个答案:

没有答案