I am trying to implement an asynchronous interface from C# Unity to C++.
This is the exposed functions in C++:
struct Vector3 {
float x;
float y;
float z;
};
extern "C" {
DLLEXPORT void sync_test(void*(Vector3[], int));
DLLEXPORT void async_test(void*(Vector3[], int));
}
They are implemented like this:
void do_work(void*(onResult)(Vector3[], int)) {
int size = 30;
Vector3* result = new Vector3[size];
for (int i = 0; i < size; i++) {
result[i] = { 5,(float)i,2 };
}
onResult(result, size);
delete[] result;
}
DLLEXPORT void sync_test(void*(onResult)(Vector3[], int)) {
do_work(onResult);
}
DLLEXPORT void async_test(void*(onResult)(Vector3[], int)) {
std::thread thread(do_work, onResult);
}
This is how i use them in C#:
[DllImport("Isosurfaces.dll")]
static extern void async_test(Action<IntPtr, int> onResult);
[DllImport("Isosurfaces.dll")]
static extern void sync_test(Action<IntPtr, int> onResult);
// Use this for initialization
void Start () {
sync_test(OnResult);
//async_test(OnResult);
}
private void OnResult(IntPtr result, int size) {
Vector3[] tris = GetTris(result, size);
Debug.Log(tris[size - 1]);
}
Vector3[] GetTris(IntPtr result, int size) {
Vector3[] tris = new Vector3[size];
int vec3Size = Marshal.SizeOf(new Vector3());
for (int i = 0; i < size; i++) {
tris[i] = (Vector3)Marshal.PtrToStructure(new IntPtr(result.ToInt32() + (i * vec3Size)), typeof(Vector3));
}
return tris;
}
When running the project in unity, sync_test
works flawlessly. The printed Vector3 matches the one created on the C++ side.
When calling async_test
instead, Unity shuts down without an error message. Looking in the Editor.log
I can't see any information that could be related to the shut down. Looking in upm.log
in the same folder I find this:
{"level":"error","message":"[Unity Package Manager (Upm)]\nParent process [12276] was terminated","timestamp":"2018-08-20T13:37:44.029Z"}
but this does not give me much of a context as to what happened.
I suspect it has something to do with my C++ code. I haven't programmed in C++ for a while so there could be some memory i forgot to free. But as of now the only memory i see that i've allocated is Vector* result
in do_work
and it is free'd right after the C# side is done processing the result.
EDIT: Changed delete result
to delete[] result
in do_work
but Unity still crashes.
async_test
creates std::thread
object which is then immediately destroyed, and std::thread::~thread()
is called in the process.
According to cppreference.com
, std::thread
destructor will call std::terminate()
if it has associated joinable thread.
Consider to add thread.detach();
line to async_test
so created thread is no longer attached to the std::thread
object.