在Lua只支持协程,并不支持系统级的线程,于是便想自己实现一个。
用法如下:
local thread=Thread.create()
thread:start()
thread:run("return arg..' world !'","hello",function(returnData)
print(returnData)
thread:quit()
end)
接口定义如下:
- create()用于创建一个线程;
- start()启动线程;
- run(script,param,callback)用于运行并处理执行结果;
- quit()退出线程;
注意参数及返回值的传递只能使用字符串进行传递,如果需要传递lua表的话,则可以使用cjson进行编码后再进行传递。
实现代码如下:
Lua的封装使用了自己写的luaobj库。
#include "luaobj/LuaState.h"
#include <pthread.h>
#include <string>
#include <queue>
#include "basics/CAScheduler.h"
class LuaThread
{
public:
//运行的参数
struct RunParam {
uint32_t reqid;
std::string script;
std::string param;
};
//返回的参数
struct ReturnParam {
unsigned int reqid;
unsigned int threadid;
std::string param;
void RunOnUIThread();
};
LuaThread();
~LuaThread();
//lua调用的接口
void Start();
void Run(RunParam *param);
void Quit();
virtual void OnRunning();
unsigned int GetID(){ return m_id; }
private:
static void* _ThreadProc(void* lpParameter);
void _initLua();
void _releaseLua();
void _onReturn(ReturnParam* param);
RunParam* _popRunParam();
LuaOwnerState* m_luaState;
pthread_t m_thread;
pthread_mutex_t m_SleepMutex;
pthread_cond_t m_SleepCondition;
pthread_mutex_t m_mutex;
std::queue<RunParam*> m_queue;
volatile bool m_quit;
unsigned int m_id;
};
#include "LuaThread.h"
#include "bind/LExtendLibs.h"
#include "basics/CAScheduler.h"
#include "manual/LuaScriptingCore.h"
unsigned int s_threadId = 0;
LuaThread::LuaThread()
:m_luaState(NULL), m_quit(true), m_id(++s_threadId)
{
pthread_mutex_init(&m_mutex, NULL);
pthread_mutex_init(&m_SleepMutex, NULL);
pthread_cond_init(&m_SleepCondition, NULL);
}
LuaThread::~LuaThread()
{
//如果没有退出则
if (!m_quit)
Quit();
pthread_mutex_destroy(&m_mutex);
pthread_mutex_destroy(&m_SleepMutex);
pthread_cond_destroy(&m_SleepCondition);
while (!m_queue.empty())
{
delete m_queue.front();
m_queue.pop();
}
}
void LuaThread::Start()
{
m_quit = false;
pthread_create(&m_thread, NULL, _ThreadProc, this);
}
void LuaThread::Run(RunParam *param)
{
pthread_mutex_lock(&m_mutex);
m_queue.push(param);
pthread_mutex_unlock(&m_mutex);
pthread_cond_signal(&m_SleepCondition);
}
void LuaThread::Quit()
{
m_quit = true;
pthread_cond_signal(&m_SleepCondition);
pthread_join(m_thread, NULL);
}
void LuaThread::OnRunning()
{
_initLua();
while (!m_quit)
{
pthread_cond_wait(&m_SleepCondition, &m_SleepMutex);
RunParam* param = _popRunParam();
while (param)
{
m_luaState->setGlobal("arg", m_luaState->newString(param->param.c_str(), param->param.length()));
LuaObject lreturn = m_luaState->doString(param->script.c_str());
ReturnParam* returnParam = new ReturnParam();
returnParam->reqid = param->reqid;
returnParam->threadid = m_id;
returnParam->param = lreturn.toString();
_onReturn(returnParam);
delete param;
param = _popRunParam();
}
}
_releaseLua();
}
void LuaThread::_initLua()
{
m_luaState = new LuaOwnerState();
RegisterExtendLibs(m_luaState);
}
void LuaThread::_releaseLua()
{
delete m_luaState;
m_luaState = NULL;
}
void* LuaThread::_ThreadProc(void* lpParameter)
{
((LuaThread*)lpParameter)->OnRunning();
return 0;
}
void LuaThread::_onReturn(ReturnParam* param)
{
CrossApp::CAScheduler::getScheduler()->performFunctionInUIThread(std::bind(&ReturnParam::RunOnUIThread,param));
}
LuaThread::RunParam* LuaThread::_popRunParam()
{
RunParam* param = NULL;
pthread_mutex_lock(&m_mutex);
if (!m_queue.empty())
{
param = m_queue.front();
m_queue.pop();
}
pthread_mutex_unlock(&m_mutex);
return param;
}
//在ui线程运行
void LuaThread::ReturnParam::RunOnUIThread()
{
LuaState* L = LuaScriptingCore::getLuaState();
LuaTable lthread = LuaTable(L->getRegistery("LuaThread")).getTable(threadid);
if (lthread.isValid())
{
LuaFunction func=lthread.getTable(reqid);
if (func.isValid())
{
func(param);
}
lthread.setTable(reqid, luaNil);
}
delete this;
}
class LuaThreadApi :public LuaClassObj
{
public:
LuaThreadApi(LuaFuncState& L)
:m_reqid(0)
{
LuaTable ltab= L.getRegistery("LuaThread");
ltab.setTable(m_impl.GetID(), L.newTable());//run的回调函数存在该表中
}
int start(LuaFuncState& L)
{
m_impl.Start();
return 0;
}
int run(LuaFuncState& L)
{
LuaThread::RunParam * param = new LuaThread::RunParam();
param->reqid = ++m_reqid;
param->script = L.arg(0).toString();
param->param = L.arg(1).toString();
if (L.arg(2).isFunction())
{
LuaTable ltab = LuaTable(L.getRegistery("LuaThread")).getTable(m_impl.GetID());
if (ltab.isTable())
{
ltab.setTable(param->reqid, L.arg(2));
}
}
m_impl.Run(param);
return 0;
}
int quit(LuaFuncState& L)
{
//回调函数置空
LuaTable ltab = L.getRegistery("LuaThread");
ltab.setTable(m_impl.GetID(), luaNil);
m_impl.Quit();
return 0;
}
BEGIN_MAP_FUNC(LuaThreadApi, "ca.Thread")
DECLARE_FUNC(start),
DECLARE_FUNC(run),
DECLARE_FUNC(quit),
END_MAP_FUNC
private:
LuaThread m_impl;
unsigned int m_reqid;
};
void RegisterLuaThread(LuaState* L)
{
L->setRegistry("LuaThread", L->newTable());
LuaClass<LuaThreadApi>::Register(L->getLuaState());
}
我的项目地址