lua多线程崩溃
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