6

スクリプトから新しいスレッドを作成できる場合、C / C ++関数をUnityスクリプトにコールバックすることは可能ですか?試しましたが、スクリプトが実行されるとすぐにUnityがクラッシュします。

私はそれについてグーグルで検索し、このスレッドを見つけました。

Unityはコールバックでもスレッドセーフでもありません。UnityEngine.Objectを拡張するクラスへのアクセスは、Unityスクリプトが実行されているのと同じスレッド内からのみ許可され、他のスレッドからの非同期やCOM/OS非同期操作からの非同期コールバックからは許可されません。

その場合、2つの方法が考えられます。

(1)これらのコールバックを取得してキューに入れるラッパーを作成し、Unityが次のイベント/データオブジェクトなどをブロックするスレッド化されていない形式で要求できるようにする関数を公開します(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

答えはイエスです!

Unity 3.5.2f2、Proライセンスを使用して、2012年8月8日に再度テストしました。@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を埋め込む必要はありませんでした。上記の2つのコードだけで、私の問題は解決しました。

于 2012-08-08T11:20:20.610 に答える