Я пытаюсь выполнить обратный вызов через 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 # Caller
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 секунд в отдельном потоке. , однако он находит, что callback является NullReference. Как я могу гарантировать, что обратный вызов не станет нулевым?