在同一个Lua状态下并行运行两个Lua线程而不发生并发执行是否安全?

我们正在使用Lua开发游戏服务器。

服务器是单线程的,我们将从C++中调用Lua。

every C++ service将从全局的Lua状态创建一个Lua线程,该状态由所有服务共享。

由Lua线程执行的Lua脚本将调用一个C API,该API将向远程服务器发出RPC调用。

然后Lua线程被暂停,因为它的C函数永远不会返回。

当RPC响应返回时,我们将继续C代码,该代码将返回给Lua脚本。

所以,我们将在同一个全局Lua状态上并行执行多个Lua线程,但它们永远不会并发运行。挂起并不是由Lua yield函数引起的,而是由C端引起的。

像这样做是否安全?

#include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>
#include "lua/lua.hpp"

static ucontext_t uctx_main, uctx_func1, uctx_func2;

lua_State* gLvm;
int gCallCnt = 0;

static int proc(lua_State *L) {
    int iID = atoi(lua_tostring(L, -1));

    printf("begin proc, %s\n", lua_tostring(L, -1));
    if(iID == 1)
    {
        swapcontext(&uctx_func1, &uctx_main);
    }
    else
    {
        swapcontext(&uctx_func2, &uctx_main);
    }
    printf("end proc, %s\n", lua_tostring(L, -1));
    return 0;
}

static void func1(void)
{
    gCallCnt++;
    printf("hello, func1\n");

    lua_State*thread = lua_newthread (gLvm);

    lua_getglobal(thread, "proc");
    char szTmp[20];
    sprintf(szTmp, "%d", gCallCnt);
    lua_pushstring(thread, szTmp);
    int iRet = lua_resume(thread, gLvm, 1);
    printf("lua_resume return:%d\n", iRet);
}

static void func2(void)
{
    gCallCnt++;
    printf("hello, func2\n");

    lua_State*thread = lua_newthread (gLvm);

    lua_getglobal(thread, "proc");
    char szTmp[20];
    sprintf(szTmp, "%d", gCallCnt);
    lua_pushstring(thread, szTmp);
    int iRet = lua_resume(thread, gLvm, 1);
    printf("lua_resume return:%d\n", iRet);
}

int main(int argc, char *argv[]){
    int iRet = 0;

    gLvm = luaL_newstate();
    luaL_openlibs(gLvm);

    lua_pushcfunction(gLvm, proc);
    lua_setglobal(gLvm, "proc");

    char func1_stack[16384];
    char func2_stack[16384];
    getcontext(&uctx_func1);
    uctx_func1.uc_stack.ss_sp = func1_stack;
    uctx_func1.uc_stack.ss_size = sizeof(func1_stack);
    uctx_func1.uc_link = &uctx_main;
    makecontext(&uctx_func1, func1, 0);

    getcontext(&uctx_func2);
    uctx_func2.uc_stack.ss_sp = func2_stack;
    uctx_func2.uc_stack.ss_size = sizeof(func2_stack);
    uctx_func2.uc_link = &uctx_main;
    makecontext(&uctx_func2, func2, 0);

    swapcontext(&uctx_main, &uctx_func1);

    swapcontext(&uctx_main, &uctx_func2);

    swapcontext(&uctx_main, &uctx_func1);

    swapcontext(&uctx_main, &uctx_func2);

    printf("hello, main\n");

    return 0;
}
点赞