简单 Lua 协同程序测试首先崩溃 运行
simple Lua corotine test crashed at first run
简而言之,测试程序在 C++ 端创建一个协程,用 Lua 端函数启动它,并使用一些日志恢复几次。它在第一次调用启动协程 运行 的 resume
时突然崩溃,侵犯了对无效堆内存的访问权限 (0xfdfdfd
)。
这是完整的代码:
#include <juce_core/juce_core.h>
#include <lauxlib.h>
int debug_log( lua_State* lua )
{
int narg = lua_gettop( lua );
juce::StringArray tokens;
for ( int i = 1; i <= narg; i++ )
tokens.add( lua_tostring( lua, i ) );
juce::Logger::writeToLog( tokens.joinIntoString( "" ) );
return 0;
}
const char* lua_code =
"function testfunc(arg1, arg2)\n"
" debug_log( \"before yield: arg1 \", arg1 )\n"
" coroutine.yield(1)\n"
" debug_log( \"after yield: arg2 \", arg2 )\n"
" coroutine.yield(2)\n"
" debug_log( \"finally in testfunc\" )\n"
"end\n";
int main()
{
auto* lua = luaL_newstate();
luaL_openlibs( lua );
lua_pushcfunction( lua, debug_log );
lua_setglobal( lua, "debug_log" );
luaL_dostring( lua, lua_code );
// create a new coroutine
auto* coro = lua_newthread( lua );
// start corotine
int t_testfunc = lua_getglobal( coro, "testfunc" );
if ( t_testfunc != LUA_TFUNCTION )
{
juce::Logger::writeToLog( "failed to get testfunc from coro: type is " + juce::String( t_testfunc ) );
exit( EXIT_FAILURE );
}
lua_pushstring( coro, "arg1" );
lua_pushnumber( coro, 123.456 );
int n_re = 0;
int status = lua_resume( lua, coro, 2, &n_re ); ///< die here
// repeatedly resume until finished
while ( true )
{
juce::Logger::writeToLog( "status: " + juce::String( status ) + " with " + juce::String( n_re ) + " returned values" );
if ( n_re > 0 )
{
juce::Logger::writeToLog( " returned value " + juce::String( lua_tostring( coro, 1 ) ) );
lua_pop( coro, n_re );
}
if ( status == LUA_YIELD )
{
status = lua_resume( lua, coro, 0, &n_re );
}
else if ( status == LUA_OK )
{
juce::Logger::writeToLog( "coroutine ended" );
break;
}
else
{
juce::Logger::writeToLog( "coroutine returned with error: " + juce::String( status ) );
exit( EXIT_FAILURE );
}
}
}
这是堆栈跟踪:
> coro_call.exe!luaH_getshortstr(Table * t, TString * key) 行 751 C++
coro_call.exe!luaT_gettmbyobj(lua_State * L, const TValue * o, TMS event) 行 83 C++
coro_call.exe!luaD_tryfuncTM(lua_State * L, StackValue * func) 行 391 C++
coro_call.exe!luaD_precall(lua_State * L, StackValue * func, int nresults) 行 559 C++
coro_call.exe!ccall(lua_State * L, StackValue * func, int nResults, int inc) 行 575 C++
coro_call.exe!resume(lua_State * L, void * ud) 行 731 C++
coro_call.exe!luaD_rawrunprotected(lua_State * L, void(*)(lua_State *, void *) f, void * ud) 行 144 C++
coro_call.exe!lua_resume(lua_State * L, lua_State * from, int nargs, int * nresults) 行 788 C++
coro_call.exe!main() 行 44 C++
是不是对Lua协程C有什么误解API?
此外,Lua官方文档对k函数和lua_pcallk
的概念给出了相当长的部分,但我好像没有在我的测试代码中的任何地方都需要它们。我应该在哪里使用这些东西?
lua_resume
的参数顺序有误
它应该是 lua_resume(coro, lua,
而不是 lua_resume(lua, coro,
concepts of k function ... Where should I use these stuffs?
有一个使用 k 函数的好例子
简而言之,测试程序在 C++ 端创建一个协程,用 Lua 端函数启动它,并使用一些日志恢复几次。它在第一次调用启动协程 运行 的 resume
时突然崩溃,侵犯了对无效堆内存的访问权限 (0xfdfdfd
)。
这是完整的代码:
#include <juce_core/juce_core.h>
#include <lauxlib.h>
int debug_log( lua_State* lua )
{
int narg = lua_gettop( lua );
juce::StringArray tokens;
for ( int i = 1; i <= narg; i++ )
tokens.add( lua_tostring( lua, i ) );
juce::Logger::writeToLog( tokens.joinIntoString( "" ) );
return 0;
}
const char* lua_code =
"function testfunc(arg1, arg2)\n"
" debug_log( \"before yield: arg1 \", arg1 )\n"
" coroutine.yield(1)\n"
" debug_log( \"after yield: arg2 \", arg2 )\n"
" coroutine.yield(2)\n"
" debug_log( \"finally in testfunc\" )\n"
"end\n";
int main()
{
auto* lua = luaL_newstate();
luaL_openlibs( lua );
lua_pushcfunction( lua, debug_log );
lua_setglobal( lua, "debug_log" );
luaL_dostring( lua, lua_code );
// create a new coroutine
auto* coro = lua_newthread( lua );
// start corotine
int t_testfunc = lua_getglobal( coro, "testfunc" );
if ( t_testfunc != LUA_TFUNCTION )
{
juce::Logger::writeToLog( "failed to get testfunc from coro: type is " + juce::String( t_testfunc ) );
exit( EXIT_FAILURE );
}
lua_pushstring( coro, "arg1" );
lua_pushnumber( coro, 123.456 );
int n_re = 0;
int status = lua_resume( lua, coro, 2, &n_re ); ///< die here
// repeatedly resume until finished
while ( true )
{
juce::Logger::writeToLog( "status: " + juce::String( status ) + " with " + juce::String( n_re ) + " returned values" );
if ( n_re > 0 )
{
juce::Logger::writeToLog( " returned value " + juce::String( lua_tostring( coro, 1 ) ) );
lua_pop( coro, n_re );
}
if ( status == LUA_YIELD )
{
status = lua_resume( lua, coro, 0, &n_re );
}
else if ( status == LUA_OK )
{
juce::Logger::writeToLog( "coroutine ended" );
break;
}
else
{
juce::Logger::writeToLog( "coroutine returned with error: " + juce::String( status ) );
exit( EXIT_FAILURE );
}
}
}
这是堆栈跟踪:
> coro_call.exe!luaH_getshortstr(Table * t, TString * key) 行 751 C++
coro_call.exe!luaT_gettmbyobj(lua_State * L, const TValue * o, TMS event) 行 83 C++
coro_call.exe!luaD_tryfuncTM(lua_State * L, StackValue * func) 行 391 C++
coro_call.exe!luaD_precall(lua_State * L, StackValue * func, int nresults) 行 559 C++
coro_call.exe!ccall(lua_State * L, StackValue * func, int nResults, int inc) 行 575 C++
coro_call.exe!resume(lua_State * L, void * ud) 行 731 C++
coro_call.exe!luaD_rawrunprotected(lua_State * L, void(*)(lua_State *, void *) f, void * ud) 行 144 C++
coro_call.exe!lua_resume(lua_State * L, lua_State * from, int nargs, int * nresults) 行 788 C++
coro_call.exe!main() 行 44 C++
是不是对Lua协程C有什么误解API?
此外,Lua官方文档对k函数和lua_pcallk
的概念给出了相当长的部分,但我好像没有在我的测试代码中的任何地方都需要它们。我应该在哪里使用这些东西?
lua_resume
的参数顺序有误
它应该是 lua_resume(coro, lua,
而不是 lua_resume(lua, coro,
concepts of k function ... Where should I use these stuffs?
有一个使用 k 函数的好例子