我将一个委托(日志记录函数)传递给非托管代码,它工作正常,除非它是从另一个线程调用的,该线程是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
时,应用程序会以无其他信息的方式静默崩溃。
答案 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 ++线程并查看它崩溃的原因。