LuaThread的实现

Stella981
• 阅读 249

在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

点赞
收藏
评论区
推荐文章
刚刚好 刚刚好
4个月前
css问题
1、在IOS中图片不显示(给图片加了圆角或者img没有父级)<div<imgsrc""/</divdiv{width:20px;height:20px;borderradius:20px;overflow:h
晴空闲云 晴空闲云
4个月前
css中box-sizing解放盒子实际宽高计算
我们知道传统的盒子模型,如果增加内边距padding和边框border,那么会撑大整个盒子,造成盒子的宽度不好计算,在实务中特别不方便。boxsizing可以设置盒模型的方式,可以很好的设置固定宽高的盒模型。盒子宽高计算假如我们设置如下盒子:宽度和高度均为200px,那么这会这个盒子实际的宽高就都是200px。但是当我们设置这个盒子的边框和内间距的时候,那
艾木酱 艾木酱
3个月前
快速入门|使用MemFire Cloud构建React Native应用程序
MemFireCloud是一款提供云数据库,用户可以创建云数据库,并对数据库进行管理,还可以对数据库进行备份操作。它还提供后端即服务,用户可以在1分钟内新建一个应用,使用自动生成的API和SDK,访问云数据库、对象存储、用户认证与授权等功能,可专
Wesley13 Wesley13
1年前
java 多线程
创建线程的4种方式1、继承Thread类,复写run方法,run方法中为线程需要执行的逻辑部分,而启动线程调用start方法。小示例见代码,通过Thread.currentThread().getName()可以获得当前线程名称publicclassMyThreadextendsThread{private
Wesley13 Wesley13
1年前
Java的编程逻辑
1、run()和start()的区别2、线程的基本属性和方法1.id:一个递增的整数,每创建一个线程就加一2.name3.优先级:从1到10,默认为5,会映射到系统中的优先级。数字越大,要优先级越高4.状态: NEW:还没调用start RUNABLE:正在执行run或者正在等待cup分配
Wesley13 Wesley13
1年前
Java面试系列
实现多线程的方式继承Thread类,重写run方法,调用start方法启动线程实现Runnable接口,重写run方法,调用start方法启动线程实现Callable接口,重写call方法,并用FutureTask包装,在newThread中传入FutureTask,然后调用start方
Wesley13 Wesley13
1年前
Java多线程基础
(1)传统使用类Thread和接口Runnable实现 1\.在Thread子类覆盖的run方法中编写运行代码方式一 newThread(){@Overridepublicvoidrun(){while(true){try{Thread.sleep(2
Stella981 Stella981
1年前
Gevent简明教程
1、前述进程线程协程异步并发编程(不是并行)目前有四种方式:多进程、多线程、协程和异步。多进程编程在python中有类似C的os.fork,更高层封装的有multiprocessing标准库多线程编程python中有Thread和threading异步编程在linux下主要有三种实现selec
Wesley13 Wesley13
1年前
Mysql优化操作学习纪录
SHOWSTATUS;FLUSHSTATUS;查看当前连接数SHOWSTATUSLIKE'Thread\_%';Thread\_cached:被缓存的线程的个数Thread\_running:处于激活状态的线程的个数Thread\_connected:当前连接的线程的个数Thread\_created:总共被创建
helloworld_28799839 helloworld_28799839
4个月前
常用知识整理
Javascript判断对象是否为空jsObject.keys(myObject).length0经常使用的三元运算我们经常遇到处理表格列状态字段如status的时候可以用到vue