【问题标题】:Asynchronous interface managed -> umanaged code异步接口托管 -> 非托管代码
【发布时间】:2018-08-20 13:56:22
【问题描述】:

我正在尝试实现从 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++ 端创建的相匹配。

改为调用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++ 编程了,所以可能有一些内存我忘记释放了。但是到目前为止,我看到的唯一分配的内存是do_work 中的Vector* result,并且在C# 端处理完结果后它是免费的。

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

【问题讨论】:

  • 您的do_work 函数调用未定义行为,因为它使用delete 而不是delete[]
  • hmmm,那它被sync_test调用时是怎么回事?
  • 未定义行为的一个可能结果是代码在某些情况下“正常”工作。 undefined这个词意味着你无法保证会发生什么。
  • thread::~thread() 调用 std::terminate 如果它有关联的可连接线程。
  • 是的,现在我想起来了!但不幸的是,使用 delete[] 会出现同样的问题。 @UnholySheep

标签: c++ multithreading unity3d asynchronous dllexport


【解决方案1】:

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

根据cppreference.comstd::thread析构函数如果有关联的joinable线程,就会调用std::terminate()

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

【讨论】:

  • 这是导致崩溃的主要问题。
【解决方案2】:

在 C++ 中释放内存:

Vector3* result = new Vector3;
delete result;

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

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

【讨论】:

  • 我更改了它,但 C# 应用程序仍然崩溃。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-24
  • 2011-11-14
  • 2011-01-29
  • 2014-07-09
  • 2015-02-24
  • 1970-01-01
相关资源
最近更新 更多