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

时间:2018-08-20 13:56:22

标签: c++ multithreading unity3d asynchronous 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));
}

它们的实现方式如下:

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

这就是我在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;
}

统一运行项目时,sync_test可以正常工作。打印的Vector3与在C ++端创建的Vector3相匹配。

当调用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"} 

但是,这并没有给我太多有关发生的情况的信息。

我怀疑这与我的C ++代码有关。我已经有一段时间没有用C ++编程了,所以可能有些内存我忘了释放。但是到目前为止,我看到我分配的唯一内存是Vector* result中的do_work,并且在C#端处理完结果后立即释放了该内存。

编辑:在delete result中将delete[] result更改为do_work,但是Unity仍然崩溃。

2 个答案:

答案 0 :(得分:6)

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

根据cppreference.com,如果std::thread析构函数具有关联的std::terminate()线程,它将调用joinable

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

答案 1 :(得分:3)

释放C ++中的内存:

Vector3* result = new Vector3;
delete result;

Vector3* result = new Vector3[size];
delete [] result;

您的result变量是一个数组,因此应使用delete [] result