以下代碼使用luabind進行lua的coroutine測試
1: void ScriptManagedChannel::OnServiceInitialize()
2: {
3: try
4: {
5: mThread = lua_newthread( GScriptScriptContext->GetVM() );
6:
7: luabind::resume_function<void>( mThread, "ScriptMain", this );
8:
9: Resume();
10: }
11: catch (std::exception& e)
12: {
13: const char* ErrorMsg = lua_tostring( GScriptScriptContext->GetVM(), -1 );
14: printf("%s\n", e.what() );
15: }
16:
17:
18: }
19:
20: void ScriptManagedChannel::Resume( )
21: {
22: luabind::resume<void>( mThread );
23: }
24:
25: void ScriptManagedChannel::StopTest( )
26: {
27: lua_yield( mThread, 0 );
28: }
29:
30:
代碼中, mThread類型為lua_State*類型
GScriptScriptContext->GetVM()是加載了代碼的lua_State*
StopTest為注冊為ScriptManagedChannel類成員函數到lua中的定義
接下來看lua端的測試代碼:
1: function ScriptMain( Channel )
2:
3:
4: for i = 1, 5 do
5:
6: print("done", i)
7:
8: Channel:StopTest( )
9:
10:
11:
12: end
13: end
剛開始,在測試代碼時, lua中有個手誤而造成的錯誤, 導致C++代碼運行到第7行時彈出assert
位於:luabind-0.9.1\luabind\detail\call_function.hpp 第264行,對應以下代碼第13行
1: ~proxy_function_void_caller()
2: {
3: if (m_called) return;
4:
5: m_called = true;
6: lua_State* L = m_state;
7:
8: int top = lua_gettop(L);
9:
10: push_args_from_tuple<1>::apply(L, m_args);
11: if (m_fun(L, boost::tuples::length<Tuple>::value, 0))
12: {
13: assert(lua_gettop(L) == top - m_params + 1);
14:
15: NO_EXCEPTIONS
16: throw luabind::error(L);
17: #else
18: error_callback_fun e = get_error_callback();
19: if (e) e(L);
20:
21: assert(0 && "the lua function threw an error and exceptions are disabled."
22: " If you want to handle the error you can use luabind::set_error_callback()");
23: std::terminate();
24: #endif
25: }
26: // pops the return values from the function call
27: stack_pop pop(L, lua_gettop(L) - top + m_params);
28: }
11行代碼中調用的是lua_resume, 返回的是運行錯誤, 但是被13行的assert擋住了, 無法通過第16行拋出異常被外面捕獲.
因此,嘗試注釋第13行, 再測試, 可以在lua拋出錯誤後, 在棧頂捕獲到coroutine函數resume時報出的錯誤信息.問題解決
對於lua的coroutine, 網上資料不多, 這裡有一篇比較詳細的代碼
我比較疑惑的是, 有沒有必要將代碼在dofile或者dobuffer時, 必須傳入newthread出的state? 如果還是傳入原始的state會有什麼影響?
歡迎各位有此經驗的討論
摘自 戰魂小築