3

luabind でコルーチンを適切に使用する方法を理解するのに苦労しています。テンプレート化された関数があります:

template<class Ret> 
Ret resume_function(object const& obj, ...)

( ) には、LuaRetから渡された値が含まれているはずです。yield

私の現在の混乱のポイントは次のとおりです。

  • 関数が を呼び出すのではなく、返された場合はどうなりますyieldか? resume_function関数の戻り値を返しますか?
  • どの (またはいくつの) パラメータが に渡されるか事前にわからない場合、この関数をどのように使用することになっていますyieldか? たとえば、可能性のある生成関数が複数ある場合、その関数は呼び出すことができます。
  • Retに複数の値が渡された場合の型はyield?

これがどのように機能するかについて、私は完全に間違っていますか?このようなことを想定しています。Lua 側:

local img = loadImage("foo.png")

loadImageは、画像を別のスレッドにロードするように要求してから を呼び出す C++ 関数でありlua_yield、しばらくして でパラメータとしてluabind::resume_function呼び出さimgれます。

パラメータとして渡す必要が"foo.png"ありますか?yieldを呼び出す前に別の関数に変更し、その後は?yieldに値を渡さないでください。yieldこれを構造化する正しい方法は何ですか?私は明らかにここで何かを誤解しています。

4

1 に答える 1

2

ここで、(Ret)には、Luaによってyieldに渡された値が含まれているはずです。

Luabindは単一の戻り値のみをサポートするため、に渡された最初の値のみを返しますcoroutine.yield

関数がyieldを呼び出すのではなく戻るとどうなりますか?resume_functionは関数の戻り値を返しますか?

はい、戻り値を取得します。

どの(またはいくつの)パラメーターが渡されて生成されるかが事前にわからない場合、この関数をどのように使用することになっていますか?たとえば、複数の可能な降伏関数がある場合、関数は呼び出すことができます。

それはあなた次第です; それらはあなたの機能です。降伏関数がパラメーターとして受け取るもの、およびコルーチンを再開する関数が提供するものについての規則を作成する必要があります。

複数の値がyieldに渡される場合、Retのタイプは何ですか?

あなたが望むものは何でも。これはテンプレートパラメータです。関数のパラメーターの数は、関数が提供する戻り値とは関係ありません。

注意:Lua関数は任意の数のパラメーターを取り、何でも返すことができます。Luabindが実行できるのは、指定したパラメーターを渡し、Lua関数からの戻り値を期待どおりの値に変換することだけです。もちろん、Luabindは戻り値の型チェックを行います。ただし、yielding/returning関数がユーザーがRetに提供するタイプに変換可能なものを返すことを確認するのはあなたの責任です。

loadImageは、画像を別のスレッドにロードするように要求してからlua_yieldを呼び出すC ++関数であり、しばらくすると、パラメーターとしてimgを使用してluabind::resume_functionが呼び出されます。

Luabindを使用している場合は、lua_yield直接電話しないでください。Luabindでyieldを実行する適切な方法は、登録した関数に属性を追加することです。この属性は、関数から戻るたびに生成されます。構文は次のとおりです。

module(L)
[
    def("do_thing_that_takes_time", &do_thing_that_takes_time, yield)
];

つまり、yieldを生成するC ++関数は、常にyieldでなければなりません。これはLuabindの制限であり、通常のLuaと同様に、適切と思われる場合に降伏するかどうかを選択できます。

また、Luaコルーチンは実際のスレッドと同じものではないことを忘れないでください。それらは先制的ではありません。それらは、withまたは同等のresume呼び出しを明示的に指示した場合にのみ実行されます。coroutine.resume

また、複数のC /C++スレッドから同じLuaインスタンスを実行しないでください。Luaは同じインスタンス内でスレッドセーフではありません(これは多かれ少なかれ同じlua_Stateオブジェクトを意味します)。

あなたがやりたいと思われるのは、LuaにC ++の関数を呼び出させ、それ自体がスレッドを生成してプロセスを実行し、そのスレッドが完了するまでLuaコードを待機させてから応答を受け取ることです。

そのためには、C++スレッドを表すオブジェクトをLuaスクリプトに与える必要があります。したがって、loadImage関数はコルーチンロジックを使用しないでください。C++スレッドを表すオブジェクトを返す必要があります。Luaスクリプトは、オブジェクトが完了したかどうかを尋ねることができ、完了した場合は、オブジェクトからデータを照会できます。

ここでコルーチンが機能する場所は、これが終了するまでLuaスクリプトを待たせたくない場合です。つまり、Luaスクリプトを頻繁に呼び出していますが、C ++スレッドが実行されていない場合は、戻る必要があります。その場合、次のようなことができます。

function loadImageAsCoroutine(imageFilename)
    local cppThread = cpp.loadImage(imageFilename);

    local function threadFunc(cppThread)
        if(cppThread:isFinished()) then
            local data = cppThread:GetImage();
            return data;
        else
            coroutine.yield();
        end
    end

    local thread = coroutine.create(threadFunc);

    local errors, data = assert(coroutine.resume(thread, cppThread));

    if(coroutine.status(thread) == "dead") then
        return data;
    else
        return thread;
    end
end

この関数は、コルーチンまたは画像データ自体を返します。この関数の呼び出し元は、タイプを確認する必要があります。タイプが「スレッド」の場合、C++スレッドはまだ終了していません。それ以外の場合は画像データです。

この関数の呼び出し元は、コルーチンを必要なだけポンピングできますcoroutine.resume(luabind :: resume_functionなど)。毎回、戻り値を確認してください。それはnil、C ++スレッドが終了していない場合であり、そうでない場合はそうではありませんnil

于 2011-06-16T04:05:43.560 に答える