6

如果您可以从脚本创建一个新线程,是否有可能将 C/C++ 函数回调到 Unity 脚本中?我试过了,但一旦脚本执行,Unity 就会崩溃。

我用谷歌搜索了一下,发现这个帖子

Unity 不是回调也不是线程安全的,对扩展 UnityEngine.Object 的类的任何访问只允许在运行统一脚本的同一线程内进行,不能与其他线程异步,也不能来自 COM / OS 异步操作的异步回调

如果你是这种情况,有两种可能的方法:

(1) 编写一个包装器来获取这些回调并将这些东西排队,然后公开一个函数,该函数允许统一请求下一个事件/数据对象或以阻塞、非线程形式的任何内容 (2) 使回调调用到某事物上的静态函数从 System.Object 扩展并编写与上述相同的逻辑来请求有关扩展 UnityEngine.Object 的类的信息

但是我认为如果我创建一个线程并回调到该线程中,就可以了,对吧?我之所以这样想,是因为我读过类似这样的线程,其中介绍了如何使 C 函数回调 C# 函数。所以我推断如果我创建一个新线程,它不再是 Unity,它只是单声道和 C#。

这是使 Unity 崩溃的代码:

C++ 代码:

#include <iostream>
// #include "stdafx.h"

typedef int (__stdcall * Callback)(const char* text);

Callback Handler = 0;

extern "C" __declspec(dllexport)
void __stdcall SetCallback(Callback handler) {
    Handler = handler;
}

extern "C" __declspec(dllexport)
void __stdcall TestCallback() {
    int retval = Handler("hello world");
}

C# 代码:

using UnityEngine;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;


class UnManagedInterop : MonoBehaviour {
  private delegate int Callback(string text);
  private Callback mInstance;   // Ensure it doesn't get garbage collected


  public void Test() {
        mInstance = new Callback(Handler);
        SetCallback(mInstance);
        TestCallback();
  }

  private int Handler(string text) {
    // Do something...
    print(text);
    return 42;
  }

  [DllImport("test0")]
  private static extern void SetCallback(Callback fn);
  [DllImport("test0")]
  private static extern void TestCallback();

    void Start()
    {
        Thread oThread = new Thread(new ThreadStart(Test));

        // Start the thread
        oThread.Start();


    }
}
4

1 回答 1

4

答案是肯定的!

我在 2012 年 8 月 8 日再次测试,使用 Unity 3.5.2f2,Pro 许可证。感谢@hatboyzero 的评论,我找到了这个例子

虽然我的问题中的代码不起作用,但以下代码有效:

// C#
using System.Runtime.InteropServices;

class Demo {
    delegate int MyCallback1 (int a, int b);

    [DllImport ("MyRuntime")]
    extern static void RegisterCallback (MyCallback1 callback1);

    static int Add (int a, int b) { return a + b; }
    static int Sub (int a, int b) { return a - b; }

    void Init ()
    {
        // This one registers the method "Add" to be invoked back by C code
        RegisterCallback (Add);
    }
}


// C
typedef int (*callback_t) (int a, int b);
static callback_t my_callback;

void RegisterCallback (callback_t cb)
{
    my_callback = cb;
}

int InvokeManagedCode (int a, int b)
{
    if (my_callback == NULL){
         printf ("Managed code has not initialized this library yet");
         abort ();
    }
    return (*my_callback) (a, b);
}

我不必像教程建议的那样嵌入 MonoRuntime。只是上面两段代码解决了我的问题。

于 2012-08-08T11:20:20.610 回答