2011-08-26 28 views
7

Sto cercando di capire come utilizzare le co-routines per "mettere in pausa" uno script e attendere che venga eseguita qualche elaborazione prima di riprendere.Lua co-routines

Forse sto guardando le co-routine nel modo sbagliato. Ma il mio tentativo è strutturato in modo simile all'esempio fornito in questo answer.

Il ciclo in loop.lua non raggiunge mai una seconda iterazione, e quindi non raggiunge mai la condizione i == 4 richiesta per uscire dal ciclo in esecuzione nel codice C. Se non cedo in loop.lua, allora questo codice si comporta come previsto.

main.cpp

#include <lua/lua.hpp> 

bool running = true; 

int lua_finish(lua_State *) { 
    running = false; 
    printf("lua_finish called\n"); 
    return 0; 
} 
int lua_sleep(lua_State *L) { 
    printf("lua_sleep called\n"); 
    return lua_yield(L,0); 
} 

int main() { 
    lua_State* L = lua_open(); 
    luaL_openlibs(L); 

    lua_register(L, "sleep", lua_sleep); 
    lua_register(L, "finish", lua_finish); 

    luaL_dofile(L, "scripts/init.lua"); 

    lua_State* cL = lua_newthread(L); 
    luaL_dofile(cL, "scripts/loop.lua"); 

    while (running) { 
     int status; 
     status = lua_resume(cL,0); 
     if (status == LUA_YIELD) { 
      printf("loop yielding\n"); 
     } else { 
      running=false; // you can't try to resume if it didn't yield 
      // catch any errors below 
      if (status == LUA_ERRRUN && lua_isstring(cL, -1)) { 
       printf("isstring: %s\n", lua_tostring(cL, -1)); 
       lua_pop(cL, -1); 
      } 
     } 
    } 

    luaL_dofile(L, "scripts/end.lua"); 
    lua_close(L); 
    return 0; 
} 

loop.lua

print("loop.lua") 

local i = 0 
while true do 
    print("lua_loop iteration") 
    sleep() 

    i = i + 1 
    if i == 4 then 
     break 
    end 
end 

finish() 

EDIT: Aggiunta una taglia, per ottenere auspicabilmente qualche aiuto su come raggiungere questo obiettivo.

risposta

2

Il codice di ritorno 2 da lua_resume è un LUA_ERRRUN. Controlla la stringa in cima allo stack Lua per trovare il messaggio di errore.

Un modello simile ha funzionato per me, anche se ho utilizzato coroutine.yield anziché lua_yield e sono in C anziché in C++. Non vedo il motivo per cui la soluzione non funzionerebbe

Sul ripristino chiamata, non è chiaro se siete più di semplificazione per un esempio, ma mi piacerebbe apportare le seguenti modifiche nel vostro ciclo while:

int status; 
status=lua_resume(cL,0); 
if (status == LUA_YIELD) { 
    printf("loop yielding\n"); 
} 
else { 
    running=false; // you can't try to resume if it didn't yield 
    // catch any errors below 
    if (status == LUA_ERRRUN && lua_isstring(cL, -1)) { 
    printf("isstring: %s\n", lua_tostring(cL, -1)); 
    lua_pop(cL, -1); 
    } 
} 

Edit 2:

Per il debug, aggiungere il seguente prima di eseguire il tuo curriculum. Hai una stringa sempre spinto sulla pila da qualche parte:

int status; 
// add this debugging code 
if (lua_isstring(cL, -1)) { 
    printf("string on stack: %s\n", lua_tostring(cL, -1)); 
    exit(1); 
} 
status = lua_resume(cL,0); 

Edit 3:

Oh santo cielo, non posso credere che non ho visto questo già, non si vuole corri luaL_dofile quando hai intenzione di cedere perché non puoi cedere un pcall direttamente come meglio so, che è ciò che accade nel dofile (5.2 passerà attraverso, ma penso che tu abbia ancora bisogno del lua_resume). Passare a questa:

luaL_loadfile(cL, "scripts/loop.lua"); 
+0

Il codice di errore 2 si verifica solo quando il codice di ripresa viene eseguito successivamente (più di uno, senza un altro rendimento). Qualsiasi altro errore che ottengo è: "tenta di chiamare un valore stringa".Il codice pop: 'if (lua_isstring (cL, -1)) { \t \t printf (" isstring:% s \ n ", lua_tostring (cL, -1)); \t \t lua_pop (cL, -1); \t} " – dcousens

+0

" tenta di chiamare una stringa "significa che qualcos'altro è nello stack diverso dalla tua routine, probabilmente un messaggio di errore. E quando il curriculum termina con un return 0, la routine è terminata e non puoi più riprenderla, non è più in pila. Puoi riprendere di nuovo solo se hai ottenuto un rendimento l'ultima volta o hai spinto una nuova routine in pila. – BMitch

+0

Come posso ottenere il messaggio di errore, se non tramite il codice sopra? – dcousens

0

ultima volta che ho dovuto vedermela con Lua coroutine ho finito con tale codice

const char *program = 
"function hello()\n" 
" io.write(\"Hello world 1!\")\n" 
" io.write(\"Hello world 2!\")\n" 
" io.write(\"Hello world 3!\")\n" 
"end\n" 
"function hate()\n" 
" io.write(\"Hate world 1!\")\n" 
" io.write(\"Hate world 2!\")\n" 
" io.write(\"Hate world 3!\")\n" 
"end\n"; 

const char raw_program[] = 
"function hello()\n" 
" io.write(\"Hello World!\")\n" 
"end\n" 
"\n" 
"cos = {}\n" 
"\n" 
"for i = 0, 1000, 1 do\n" 
" cos[i] = coroutine.create(hello)\n" 
"end\n" 
"\n" 
"for i = 0, 1000, 1 do\n" 
" coroutine.resume(cos[i])\n" 
"end"; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    lua_State *L = lua_open(); 
    lua_State *Lt[1000]; 
    global_State *g = G(L); 

    printf("Lua memory usage after open: %d\n", g->totalbytes); 

    luaL_openlibs(L); 

    printf("Lua memory usage after openlibs: %d\n", g->totalbytes); 

    lua_checkstack(L, 2048); 

    printf("Lua memory usage after checkstack: %d\n", g->totalbytes); 

    //lua_load(L, my_lua_Reader, (void *)program, "code"); 
    luaL_loadbuffer(L, program, strlen(program), "line"); 

    printf("Lua memory usage after loadbuffer: %d\n", g->totalbytes); 

    int error = lua_pcall(L, 0, 0, 0); 
    if (error) { 
     fprintf(stderr, "%s", lua_tostring(L, -1)); 
     lua_pop(L, 1); 
    } 

    printf("Lua memory usage after pcall: %d\n", g->totalbytes); 

    for (int i = 0; i < 1000; i++) { 
     Lt[i] = lua_newthread(L); 
     lua_getglobal(Lt[i], i % 2 ? "hello" : "hate"); 
    } 

    printf("Lua memory usage after creating 1000 threads: %d\n", g->totalbytes); 

    for (int i = 0; i < 1000; i++) { 
     lua_resume(Lt[i], 0); 
    } 

    printf("Lua memory usage after running 1000 threads: %d\n", g->totalbytes); 

    lua_close(L); 

    return 0; 
} 

Sembra che non si poteva caricare file come coroutine? ma usa invece la funzione E dovrebbe essere selezionato in cima alla pila.

lua_getglobal(Lt[i], i % 2 ? "hello" : "hate"); 
+1

Non c'è bisogno di creare la coroutine nello script Lua, la chiamata 'lua_newthread' lo fa in C/C++. Lo uso da solo senza problemi. – BMitch

+0

In realtà non carico raw_program. Dovrei tagliarlo dal mio post. Ma sì, vedo. Il problema è con la ripresa della coroutine. non iniziarli. dovresti leggere attentamente il post originale – yatagarasu

+0

Hai appena visto che stai usando 'lua_newthread' nel tuo esempio. Ma sì, l'OP ha problemi dopo aver ceduto la coroutine. – BMitch