lua多线程崩溃

DADA_dotnet 2016-08-11 12:22:11

c++多线程调用lua方法,会时不时崩溃。
修改了lua源代码lua_lock和lua_unlock宏,加锁情况下也是会崩溃(参考http://www.cnblogs.com/zhangdongsheng/p/3679024.html)
下面是我的代码。


=========================================== test.lua 测试代码如下:

local t = Thread:getInstance(); // 这里是下面c++映射到lua的方法
for i = 1, 10, 1 do
// 启动c++线程执行下面lua方法
t:start(function()
// 这里是新线程里处理
for j = 1, 100000, 1 do
G:log(i .. " #### j:" .. tostring(j));
end
end);
end


=========================================== lua_thread.cpp 代码如下:(下面代码是注册Thread.h中的函数为lua)
lua中可以通过
local t = Thread:getInstance(); 获得线程对象,也可以 local t = Thread:new();
t:start(function()
// 这里是新线程里处理
end);
--------------------------------------------

/*
** Lua binding: ThreadToLua
*/

#include "lua_thread.hpp"

#ifndef __cplusplus
#include "stdlib.h"
#endif
#include "string.h"
#include "tolua_fix.h"
#include "Thread.h"

#include "CCLuaValue.h"
USING_NS_CC;

/* Exported function */
//TOLUA_API int register_lua_thread(lua_State* tolua_S);

/* function to register type */
static void tolua_reg_types(lua_State* tolua_S)
{
tolua_usertype(tolua_S, "Thread");
}

/* method: getInstance of class Thread */
#ifndef TOLUA_DISABLE_tolua_thread_getInstance
static int tolua_thread_getInstance(lua_State* tolua_S)
{
#ifndef TOLUA_RELEASE
tolua_Error tolua_err;
if (
!tolua_isusertable(tolua_S, 1, "Thread", 0, &tolua_err) ||
!tolua_isnoobj(tolua_S, 2, &tolua_err)
)
goto tolua_lerror;
else
#endif
{
{
Thread* tolua_ret = (Thread*)Thread::getInstance();
tolua_pushusertype(tolua_S, (void*)tolua_ret, "Thread");
}
}
return 1;
#ifndef TOLUA_RELEASE
tolua_lerror :
tolua_error(tolua_S, "#ferror in function 'getInstance'.", &tolua_err);
return 0;
#endif
}
#endif //#ifndef TOLUA_DISABLE}

/* method: newInstance of class Thread */
#ifndef TOLUA_DISABLE_tolua_thread_newInstance
static int tolua_thread_newInstance(lua_State* tolua_S)
{
#ifndef TOLUA_RELEASE
tolua_Error tolua_err;
if (
!tolua_isusertable(tolua_S, 1, "Thread", 0, &tolua_err) ||
!tolua_isnoobj(tolua_S, 2, &tolua_err)
)
goto tolua_lerror;
else
#endif
{
{
Thread* tolua_ret = (Thread*)Thread::newInstance();
tolua_pushusertype(tolua_S, (void*)tolua_ret, "Thread");
}
}
return 1;
#ifndef TOLUA_RELEASE
tolua_lerror :
tolua_error(tolua_S, "#ferror in function 'newInstance'.", &tolua_err);
return 0;
#endif
}
#endif //#ifndef TOLUA_DISABLE

/* method: start of class Thread */
#ifndef TOLUA_DISABLE_tolua_thread_start
static int tolua_thread_start(lua_State* tolua_S)
{
#ifndef TOLUA_RELEASE
tolua_Error tolua_err;
if (
!tolua_isusertype(tolua_S, 1, "Thread", 0, &tolua_err) ||
//!tolua_isnumber(tolua_S,2,0,&tolua_err) ||
!toluafix_isfunction(tolua_S, 2, "LUA_FUNCTION", 0, &tolua_err) ||
!tolua_isnoobj(tolua_S, 3, &tolua_err)
)
goto tolua_lerror;
else
#endif
{
Thread* self = (Thread*)tolua_tousertype(tolua_S, 1, 0);
//int luaCallback = ((int) tolua_tonumber(tolua_S,2,0));
LUA_FUNCTION luaCallback = (toluafix_ref_function(tolua_S, 2, 0));
#ifndef TOLUA_RELEASE
if (!self) tolua_error(tolua_S, "invalid 'self' in function 'start'", NULL);
#endif
{
self->start(luaCallback);
}
}
return 0;
#ifndef TOLUA_RELEASE
tolua_lerror :
tolua_error(tolua_S, "#ferror in function 'start'.", &tolua_err);
return 0;
#endif
}
#endif //#ifndef TOLUA_DISABLE

/* Open function */
TOLUA_API int register_lua_thread(lua_State* tolua_S)
{
tolua_open(tolua_S);
tolua_reg_types(tolua_S);
tolua_module(tolua_S, NULL, 0);
tolua_beginmodule(tolua_S, NULL);
tolua_cclass(tolua_S, "Thread", "Thread", "", NULL);
tolua_beginmodule(tolua_S, "Thread");
tolua_function(tolua_S, "getInstance", tolua_thread_getInstance);
tolua_function(tolua_S, "new", tolua_thread_newInstance);
tolua_function(tolua_S, "start", tolua_thread_start);
tolua_endmodule(tolua_S);
tolua_endmodule(tolua_S);
return 1;
}

#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501
TOLUA_API int luaopen_thread(lua_State* tolua_S) {
return register_lua_thread(tolua_S);
};
#endif


=========================================== Thread.h 代码如下:

#ifndef __LUA_Thread_H__
#define __LUA_Thread_H__

#include "cocos2d.h"
#include "CCLuaStack.h"
#include "ThreadSafeQueue.h"

class Thread
{
public:
Thread();
~Thread();

static inline Thread* getInstance()
{
static Thread *pInstance = nullptr;
if (nullptr == pInstance)
{
pInstance = new Thread();
}
return pInstance;
}

static inline Thread* newInstance()
{
Thread *pInstance = new Thread();
return pInstance;
}

void start(int luaFunctionId);

private:
void handleLuaFunctionQueue(cocos2d::LuaStack* newthread);
void execThreadLuaFunction(cocos2d::LuaStack* newthread, int luaFunctionId);
ThreadSafeQueue<int> luaFunctionQueue;
cocos2d::LuaStack* newthread = NULL;
};

#endif


=========================================== Thread.cpp 代码如下:(主要看这部分代码实现c++多线程调用lua)

#include "Thread.h"
#include "CCLuaEngine.h"

#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
#include <windows.h>
#else
#include <unistd.h>
#endif


Thread::Thread()
{
luaFunctionQueue.clear();
}

Thread::~Thread()
{
luaFunctionQueue.clear();
CC_SAFE_RELEASE(newthread);
}


void Thread::start(int luaFunctionId)
{
if (luaFunctionQueue.empty())
{
luaFunctionQueue.push_back(luaFunctionId);

// 如果之前创建过,这里就删除,下面重新创建
CC_SAFE_RELEASE(newthread);

// 在新线程启动之前复制创建栈,并且一个线程只配一个LuaState
lua_State* L1 = cocos2d::LuaEngine::getInstance()->getLuaStack()->getLuaState();
newthread = cocos2d::LuaStack::newthread(L1); // 这里newthread作为全局变量防止被回收,导致出问题

// 创建新的系统线程并从主线程分离出来作为子线程(子线程执行完会自动销毁)
cocos2d::log("########## Thread start ##########");
auto t = std::thread([&]() {
handleLuaFunctionQueue(newthread);
});
t.detach();
}
else
{
luaFunctionQueue.push_back(luaFunctionId);
}
}

void Thread::handleLuaFunctionQueue(cocos2d::LuaStack* newthread)
{
if (!luaFunctionQueue.empty())
{
int luaFunctionId = luaFunctionQueue.front();
execThreadLuaFunction(newthread, luaFunctionId);
luaFunctionQueue.pop_front();

// 递归执行队列下一个luaFunctionId
handleLuaFunctionQueue(newthread);
}
}

void Thread::execThreadLuaFunction(cocos2d::LuaStack* newthread, int luaFunctionId)
{
if (luaFunctionId) {
cocos2d::log("########## start luaFunctionId = %d", luaFunctionId);
newthread->executeFunctionByHandler(luaFunctionId, 0);
cocos2d::log("########## end luaFunctionId = %d", luaFunctionId);
}
}


=========================================== ThreadSafeQueue.h 代码如下:
#ifndef _THREADSAFEQUEUE_H_
#define _THREADSAFEQUEUE_H_

template<typename T>
class ThreadSafeQueue
{
public:
void push_back( T && item ) {
std::lock_guard<std::mutex> g( _mutex );
_q.push_back( std::forward<T>(item) );
}

void push_back( T const & item ) {
std::lock_guard<std::mutex> g( _mutex );
_q.push_back( item );
}

T &front(){
std::lock_guard<std::mutex> g( _mutex );
return _q.front();
}

void pop_front() {
std::lock_guard<std::mutex> g( _mutex );
if ( !_q.empty() )
{
_q.pop_front();
}
}

bool empty() {
std::lock_guard<std::mutex> g( _mutex );
return _q.empty();
}

void clear() {
std::lock_guard<std::mutex> g( _mutex );
_q.clear();
}

void clear( std::function< void( T & ) > f ) {
std::lock_guard<std::mutex> g( _mutex );
for( auto &o : _q ) f( o );
_q.clear();
}

private:
std::mutex _mutex;
std::deque<T> _q;
};

#endif
...全文
2011 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
zerozerg2006 2016-10-19
  • 打赏
  • 举报
回复
话说lua不是只有一个线程吗,这种多线程去掉用lua的写法似乎本身就不合理?
DADA_dotnet 2016-08-11
  • 打赏
  • 举报
回复
下面是cocos2dx-lua项目的 CCLuaStack.cpp 部分代码,可不看。(主要是上面Thread.cpp用到了newthread方法和executeFunctionByHandler这两个方法) 代码太多发不了,只发用到的。 LuaStack *LuaStack::newthread(lua_State *L) { lua_State* L2 = lua_newthread(L); LuaStack *stack = new (std::nothrow) LuaStack(); stack->initWithLuaState(L2); //stack->autorelease(); return stack; } bool LuaStack::initWithLuaState(lua_State *L) { _state = L; return true; } int LuaStack::executeFunctionByHandler(int nHandler, int numArgs) { int ret = 0; if (pushFunctionByHandler(nHandler)) /* L: ... arg1 arg2 ... func */ { if (numArgs > 0) { lua_insert(_state, -(numArgs + 1)); /* L: ... func arg1 arg2 ... */ } ret = executeFunction(numArgs); } lua_settop(_state, 0); return ret; } bool LuaStack::pushFunctionByHandler(int nHandler) { toluafix_get_function_by_refid(_state, nHandler); /* L: ... func */ if (!lua_isfunction(_state, -1)) { CCLOG("[LUA ERROR] function refid '%d' does not reference a Lua function", nHandler); lua_pop(_state, 1); return false; } return true; } int LuaStack::executeFunction(int numArgs) { int functionIndex = -(numArgs + 1); if (!lua_isfunction(_state, functionIndex)) { CCLOG("value at stack [%d] is not function", functionIndex); lua_pop(_state, numArgs + 1); // remove function and arguments return 0; } int traceback = 0; lua_getglobal(_state, "__G__TRACKBACK__"); /* L: ... func arg1 arg2 ... G */ if (!lua_isfunction(_state, -1)) { lua_pop(_state, 1); /* L: ... func arg1 arg2 ... */ } else { lua_insert(_state, functionIndex - 1); /* L: ... G func arg1 arg2 ... */ traceback = functionIndex - 1; } int error = 0; ++_callFromLua; error = lua_pcall(_state, numArgs, 1, traceback); /* L: ... [G] ret */ --_callFromLua; if (error) { if (traceback == 0) { CCLOG("[LUA ERROR] %s", lua_tostring(_state, - 1)); /* L: ... error */ lua_pop(_state, 1); // remove error message from stack } else /* L: ... G error */ { lua_pop(_state, 2); // remove __G__TRACKBACK__ and error message from stack } return 0; } // get return value int ret = 0; if (lua_isnumber(_state, -1)) { ret = (int)lua_tointeger(_state, -1); } else if (lua_isboolean(_state, -1)) { ret = (int)lua_toboolean(_state, -1); } // remove return value from stack lua_pop(_state, 1); /* L: ... [G] */ if (traceback) { lua_pop(_state, 1); // remove __G__TRACKBACK__ from stack /* L: ... */ } return ret; }

721

社区成员

发帖
与我相关
我的任务
社区描述
Cocos2d-x相关内容讨论专区
社区管理员
  • Cocos2d-x
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧