LuaThread的实现

Stella981
• 阅读 606

在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

点赞
收藏
评论区
推荐文章
wanQQ wanQQ
2年前
Java学习 Day01 多线程
Java学习Day01多线程Java多线程实现方式有2种1.继承Thread类,重写run方法案例测试类Thread01Javapackagetop.wanqq.thread;/@authorwanqq/publicclassThread01extendsThread@Overridepubli
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
java 多线程
创建线程的4种方式1、继承Thread类,复写run方法,run方法中为线程需要执行的逻辑部分,而启动线程调用start方法。小示例见代码,通过Thread.currentThread().getName()可以获得当前线程名称publicclassMyThreadextendsThread{private
Wesley13 Wesley13
3年前
java多线程实现的三种方式
JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。1、继承Thread类实现多线程继承Thread类的方法尽管被我列为一种多线程实现方式,但Thread本质上也是实现
Wesley13 Wesley13
3年前
java多线程相关
Runnablerunnable是线程实现的一种方式(接口实现),它只有一个run()函数,用于将耗时操作写在其中,该函数没有返回值。然后使用某个线程去执行该runnable的实现运行多线程程序,Thread类在调用start()函数后就是执行的是runnable的run()函数。runnable的声明如下:publicinterfac
Wesley13 Wesley13
3年前
Java的编程逻辑
1、run()和start()的区别2、线程的基本属性和方法1.id:一个递增的整数,每创建一个线程就加一2.name3.优先级:从1到10,默认为5,会映射到系统中的优先级。数字越大,要优先级越高4.状态: NEW:还没调用start RUNABLE:正在执行run或者正在等待cup分配
Wesley13 Wesley13
3年前
Java面试系列
实现多线程的方式继承Thread类,重写run方法,调用start方法启动线程实现Runnable接口,重写run方法,调用start方法启动线程实现Callable接口,重写call方法,并用FutureTask包装,在newThread中传入FutureTask,然后调用start方
Wesley13 Wesley13
3年前
Java多线程基础
(1)传统使用类Thread和接口Runnable实现 1\.在Thread子类覆盖的run方法中编写运行代码方式一 newThread(){@Overridepublicvoidrun(){while(true){try{Thread.sleep(2
Stella981 Stella981
3年前
Gevent简明教程
1、前述进程线程协程异步并发编程(不是并行)目前有四种方式:多进程、多线程、协程和异步。多进程编程在python中有类似C的os.fork,更高层封装的有multiprocessing标准库多线程编程python中有Thread和threading异步编程在linux下主要有三种实现selec
Wesley13 Wesley13
3年前
Java创建多线程的几种方式
Java创建多线程的几种方式\TOC\1、继承Thread类,重写run()方法//方式1packagecn.itcats.thread.Test1;publicclassDemo1extendsThread{