Луабинд и сопрограммы - PullRequest
3 голосов
/ 16 июня 2011

У меня возникли проблемы с пониманием того, как правильно использовать сопрограммы с luabind. Есть шаблонная функция:

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

Где (Ret) должен содержать значения, переданные Lua в 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? Как правильно структурировать это? Я явно что-то здесь неправильно понимаю.

1 Ответ

2 голосов
/ 16 июня 2011

Где (Ret) должен содержать значения, передаваемые Lua для передачи.

Luabind поддерживает только одиночные возвращаемые значения, поэтому он вернет только первое значение, переданное coroutine.yield.

Что произойдет, если функция вернет, а не вызовет yield?Функция resume_function возвращает возвращаемое значение функции?

Да, вы получаете его возвращаемое значение.

Как вы должны использовать эту функцию, если не знаете заранеевремя, которое (или сколько) параметров будет передано для получения?Например, если существует несколько возможных функций выдачи, функция может вызвать эту функцию.

Это зависит от вас;это твои функции.Вы должны разработать соглашения о том, что приносящая функция (и) получает в качестве параметров, и что обеспечивает функция, возобновляющая сопрограмму.

Каков тип Ret, если несколько значений передаются в yield?

Что бы вы ни хотели.Это параметр шаблона.Количество параметров функции не имеет отношения к возвращаемым значениям, которые предоставляет функция.

Помните: функции Lua принимают любое количество параметров и могут возвращать что угодно.Все, что может сделать Luabind, - это передать заданные вами параметры и преобразовать возвращаемое значение из функций Lua в ожидаемое вами возвращаемое значение.Конечно же, Luabind выполнит проверку типа возвращаемого значения.Но вы несете ответственность за то, чтобы функции, возвращающие / возвращающие функции, возвращали что-то, что можно преобразовать в тип, предоставленный пользователем для Ret.

loadImage была бы функцией C ++, которая запрашивает изображение длязагружается в другой поток, а затем вызывает lua_yield, а через некоторое время luabind :: resume_function вызывается с параметром img.

Если вы используете Luabind, никогда не вызывайте lua_yield напрямую.Правильный способ выхода в Luabind - это добавить в зарегистрированную вами функцию атрибут, который будет возвращаться всякий раз, когда вы возвращаетесь из функции.Синтаксис следующий:

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

То есть функция C ++, которая выдает, должна всегда давать.Это ограничение Luabind, так как с обычным Lua вы можете выбирать, уступать или нет, как считаете нужным.

Кроме того, не забывайте, что сопрограммы Lua - это не то же самое, что реальные потоки.Они не являются преимущественными;они будут только исполняться, когда вы явно скажете им с помощью coroutine.resume или эквивалентного вызова возобновления.

Кроме того, вы никогда не должны запускать один и тот же экземпляр Lua из несколькихC / C ++ темы;Lua не является потокобезопасным в одном и том же экземпляре (что более или менее означает тот же объект lua_State).

То, что вы хотите сделать, это заставить Lua вызывать некоторую функцию в C ++, которая сама порождает поток для выполнениянекоторый процесс, затем заставьте код Lua дождаться завершения потока и затем получить ответ.

Чтобы сделать это, вам нужно предоставить сценарию Lua объект, представляющий поток C ++.Таким образом, ваша 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 в противном случае.

...