从另一个线程(Android)中的非托管代码调用Unity C#委托

时间:2017-08-03 22:23:57

标签: c# android c++ multithreading

我将一个委托(日志记录函数)传递给非托管代码,它工作正常,除非它是从另一个线程调用的,该线程是C ++库的内部。 我读了this,但我找不到任何有关C ++线程涉及的内容的信息。这肯定是线程问题,因为当我从Unity调用非托管函数的同一个线程中调用它时,委托工作。

C#

public class SomeClass : MonoBehaviour 
{
    public delegate void LibLogHandler(int a);
    private LibLogHandler handlerDelegate;

    [DllImport ("mylibrary")]
    private static extern bool library_init (string arg1, string arg2, LibLogHandler logHandler);

    public void goNow()
    {
        this.handlerDelegate = new LibLogHandler (this.logHandler);
        bool res = library_init ("someArg1", "someArg2", this.handlerDelegate);
        Debug.Log ("library init: " + res);
    }

    void logHandler(int a)
    {
        Debug.Log ("[library] " + a);
    }
}

C ++标题

extern "C" {

    typedef void (*LibLog) (int a);

    bool library_init(const char* arg1, const char* arg3, LibLog libLog);
}

C ++来源

static boost::asio::io_service IoService;
static boost::thread aThread;
static boost::shared_ptr<boost::asio::io_service::work> ThreadWork;

bool library_init(const char* arg1, const char* arg2, LibLog libLog)
{
#ifdef THREAD_ENABLED
    ThreadWork.reset(new boost::asio::io_service::work(IoService));
    aThread = boost::thread([](){
        IoService.run();
    });        
    IoService.dispatch([libLog]{
        libLog(100);
    });
#else
    libLog(10);
#endif
    return true;
}

因此,当定义THREAD_ENABLED时,应用程序会以无其他信息的方式静默崩溃。

2 个答案:

答案 0 :(得分:1)

我发现了问题 - this article对于理解从本机插件调用的回调的特性非常有用。简而言之,在托管代码(C#)中,只需要确保委托对象在此期间是持久的(引用的),而可以从非托管代码调用它。 无需担心关于使用GCHandle固定内存,因为托管运行时环境会自动为委托对象创建一个非托管存根句柄,该句柄维护其内容。无论垃圾收集器操作如何。此存根句柄将在后台传递给非托管函数。

答案 1 :(得分:0)

Unity不支持线程,您无法在其他线程中使用它。

尝试使用

bool res;
try{
    res = library_init ("someArg1", "someArg2", this.handlerDelegate);
}catch (System.Exception e){
    Debug.LogError(e.Message);
    throw;
}

弄错你的帖子。

EDIT 我想知道我的第一个陈述是否属实。我认为Debug.Log()应该是安全的。如果是这样的话,你应该调试你的C ++线程并查看它崩溃的原因。