Hello,
I'm currently playing with coroutine with Lua and Sol and I'm actually a bit confused.
Indeed, I'm trying to reproduce something like that:
Lua Code:
co1 = coroutine.create(
function()
print("AA : Step 1")
coroutine.yield()
print("AA : Step 2")
end
)
coroutine.resume(co1)
co2 = coroutine.create(
function()
print("BB : Step 1")
coroutine.yield()
print("BB : Step 2")
end
)
coroutine.resume(co2)
coroutine.resume(co1)
Output:
$ lua test.lua
AA : Step 1
BB : Step 1
AA : Step 2
So I wanted to be able to do the same thing using sol::coroutine, but it seems that the wrong coroutine is executed:
#include <sol/sol.hpp>
#include <iostream>
int main()
{
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::package, sol::lib::coroutine);
lua["print"] = [](const sol::lua_value &v){
std::cout << v.as<std::string>() << std::endl;
};
lua["cyield"] = sol::yielding([](){
std::cout << "YIELDING" << std::endl;
});
sol::coroutine co1 = lua.load(R"(
print("AA : Step 1")
cyield()
print("AA : Step 2")
)");
co1();
sol::coroutine co2 = lua.load(R"(
print("BB : Step 1")
cyield()
print("BB : Step 2")
)");
co2();
co1();
return 0;
}
Output :
AA : Step 1
YIELDING
AA : Step 2
AA : Step 1
YIELDING
I read some things about using sol::thread but I don't understand the way I should use it, for me I don't want to multithread my code, so I don't know if I'm on the good way.
Thanks for your help !
So, the reason you need sol::thread is because each of those coroutines needs its _own execution stack_. I call sol::thread by that name because that's how the Lua API and documentation refers to such an entity: a "thread".
coroutine.create(...) is hella wrong by Lua here, because coroutine.create doesn't return you a coroutine: it returns you a _thread_ (an execution stack) with an associated coroutine.
In reality, it's closer to sol::execution_stack. It is a context in which the coroutine runs, and each coroutine needs its own sol::thread to have independent variables that don't clash with one another and its own return types. That's why the examples (https://sol2.readthedocs.io/en/latest/api/coroutine.html#yield-main-thread) go through some shenanigans, to give you the right code:
#include <sol/sol.hpp>
#include <iostream>
int main()
{
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::package, sol::lib::coroutine);
lua["print"] = [](sol::object v){
std::cout << v.as<std::string>() << std::endl;
};
lua["cyield"] = sol::yielding([](){
std::cout << "YIELDING" << std::endl;
});
// notice the new threads!
sol::thread thread1 = sol::thread::create(lua);
sol::thread thread2 = sol::thread::create(lua);
// notice we load it FROM the new "execution stack"
// we need it to have thread1's stack perspective
sol::coroutine co1 = thread1.state().load(R"(
print("AA : Step 1")
cyield()
print("AA : Step 2")
)");
// call first coroutine here
co1();
// notice we load it FROM the new "execution stack"
// we need it to have thread2's stack and perspective
sol::coroutine co2 = thread2.state().load(R"(
print("BB : Step 1")
cyield()
print("BB : Step 2")
)");
// run the other coroutine
co2();
co1();
// tada! they run on
// independent stacks
return 0;
}
Given the number of times this has happened, I'm beginning to think I should write a sol::bundled_coroutine and completely change the docs to have people use that, where it automatically creates a new stack to be paired with every coroutine. The current interface is one-to-one with low-level concepts, and honestly that's causing people more heartache than benefit right now...
(To be clear, there is no sol::execution_stack. It doesn't exist; it's just a better name than sol::thread. Still, I need a good name for something like coroutine_but_it_has_the_thread_too...)
Thanks a lot for your reply, indeed this naming and the context itself is a bit confusing, maybe something named like coroutine_context could make it ?
Current name idea so far is sol::packed_coroutine.
This is also going to make me create a sol3 header. where I create aliases under a sol3:: namespace using _good_ names for everything....
Most helpful comment
Current name idea so far is
sol::packed_coroutine.This is also going to make me create a
sol3header. where I create aliases under asol3::namespace using _good_ names for everything....