文档章节

LuaThread的实现

z
 zentel
发布于 2017/04/27 21:53
字数 641
阅读 45
收藏 0

在Lua只支持协程,并不支持系统级的线程,于是便想自己实现一个。

用法如下:

local thread=Thread.create()
thread:start()
thread:run("return arg..' world !'","hello",function(returnData)
	print(returnData)
	thread:quit()
end)

接口定义如下:

  1. create()用于创建一个线程;
  2. start()启动线程;
  3. run(script,param,callback)用于运行并处理执行结果;
  4. 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());
}

我的项目地址

https://git.oschina.net/zentel/nano-CrossApp

© 著作权归作者所有

z

zentel

粉丝 0
博文 2
码字总数 1094
作品 1
合肥
私信 提问
关于LUA+Unity开发_toLua篇【一】

网上有许多的LUA与Unity插件,如toLua,uLua, sLua, xLua。 uniLua由于其复杂的集成使用过程,已经被主流所抛弃了。在对各个插件使用过之后,出此系列博客与大家分享一下心得。 前面两篇计划...

AveryHuo
2018/01/13
4.5K
0

没有更多内容

加载失败,请刷新页面

加载更多

没有更多内容

skywalking(容器部署)

skywalking(容器部署) 标签(空格分隔): APM [toc] 1. Elasticsearch SkywalkingElasticsearch 5.X(部分功能报错、拓扑图不显示) Skywalking需要Elasticsearch 6.X docker network create......

JUKE
5分钟前
1
0
解决Unable to find a single main class from the following candidates [xxx,xxx]

一、问题描述 1.1 开发环境配置 pom.xml <plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><!--一定要对上springboot版本号,因......

TeddyIH
6分钟前
0
0
Dubbo服务限制大数据传输抛Data length too large: 13055248, max payload: 8388608解决方案

当dubbo服务提供者向消费层传输大数据容量数据时,会受到Dubbo的限制,报类似如下异常: 2019-08-23 11:04:31.711 [ DubboServerHandler-XX.XX.XX.XXX:20880-thread-87] - [ ERROR ] [com.al...

huangkejie
9分钟前
0
0
HashMap和ConcurrentHashMap的区别

为了线程安全,ConcurrentHashMap 引入了一个 “分段锁” 的概念。具体可以理解把一个大的 map 拆分成 N 个小的 Map 。最后再根据 key.hashcode( )来决定放到哪一个 hashmap 中去。 hashmap ...

Garphy
10分钟前
0
0
购买SSL证书需要注意哪些问题

为了保障网站的基本安全,为网站部署SSL证书,已经是一种常态了。各大浏览器对于安装了SSL证书的网站会更友好,并且不会发出“不安全”的提示。部署SSL证书之前首先得去给网站购买一个SSL证书...

安信证书
39分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部