托管异步接口 - >非托管代码

Tag*_*gor 3 c++ multithreading asynchronous unity-game-engine dllexport

我正在尝试实现从C#Unity到C++的异步接口.

这是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));
}
Run Code Online (Sandbox Code Playgroud)

它们是这样实现的:

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);
}
Run Code Online (Sandbox Code Playgroud)

这是我在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;
}
Run Code Online (Sandbox Code Playgroud)

在统一运行项目时,sync_test工作完美无瑕.打印的Vector3与在C++端创建的匹配.

在调用时async_test,Unity会在没有错误消息的情况下关闭.看着Editor.log我看不到任何可能与关闭有关的信息.在upm.log同一文件夹中查找我发现:

{"level":"error","message":"[Unity Package Manager (Upm)]\nParent process [12276] was terminated","timestamp":"2018-08-20T13:37:44.029Z"} 
Run Code Online (Sandbox Code Playgroud)

但这并没有给我很多关于发生了什么的背景.

我怀疑它与我的C++代码有关.我没有在C++中编程一段时间,所以可能会有一些内存我忘了免费.但是到目前为止,我看到我分配的唯一内存是Vector* result在,do_work并且在C#端完成处理结果之后它是免费的.

编辑:改变delete resultdelete[] resultdo_work,但团结仍然崩溃.

小智 6

async_test创建std::thread然后立即销毁的对象,并std::thread::~thread()在此过程中调用.

根据cppreference.com,std::thread析构函数将调用std::terminate()它是否具有关联的可连接线程.

考虑添加thread.detach();行,async_test这样创建的线程不再附加到std::thread对象.