中文版 | English

网站首页 | 个人作品 | 站长日志 | 给我留言 | 经典分享 | 友情链接 | 黑白人生


c++多线程lua的实现方式

但在 C++ 项目中集成 Lua,遇到的第一个问题就是多线程问题。Lua 本身是不知晓宿主程序线程环境的,所以 lua_State 的多线程访问是不安全的。而多线程又是服务端程序的天然特性,我暂时还不想把所有逻辑都托管给 Lua,用它自己的多线程机制。所以看起来有下面几个选择: 一是把 Lua 脚本也看成是一个独立服务,通过 RPC 或者消息队列的方式去调用它,在 Lua 脚本内部处理性能问题。这样做相当于用 Lua 写了个服务,脚本复杂度比较高,偏离了我的本意。 二是在每个 C++ 线程里,都创建一个独立的 Lua VM。每个线程有自己的上下文,也自然就互不干扰了。这样做会浪费一些内存,但考虑到 Lua VM 几十 K 级别的大小,对服务端来说根本不算什么开销。但创建线程级的 Lua VM,内存管理上又有不同的方法。 __thread 修饰符只能约束 POD 变量,的确可以存 lua_State 指针,可是它不支持指针的销毁,必须自己额外管理 lua_State 对象,然后再把指针传给线程变量。thread_local 的确能支持复杂类型,可以在析构里销毁 lua_State,可又要求 C++11。思来想去,用pthread_key_create/delete + pthread_get/setspecific 是一个相对稳妥又较为简单的方法,即不用额外自动管理内存,又能实现在线程结束后自动析构线程自己的 Lua VM。 三是将 C++ 的线程与 Lua 的线程对应起来,使用同一个 Lua VM,但在每个 C++ 线程中都用lua_newthread 创建一个 Lua 线程 State 指针。不过在创建线程那一刻,仍然需要对主 lua_State 加锁。这其实相当于给每个 C++ 线程都创建了一个独立的 Lua 堆栈,这样在传参和执行脚本的时候就不担心有数据冲突。理论上来讲效果应该与二是类似的。 四是使用一个线程安全的对象池。将 lua_State 指针放到对象池里,需要的时候拿出来,用完再放回去,由对象池来管理创建和销毁。这就需要一个额外的内存管理容器,代码量大一些,只是对很多成熟的产品来说,可能本身就有这样的轮子。 考虑到代码量,复杂度等问题,我实际在项目中采取了二方案。不过我对 Lua 的了解还不深入,不知道是否还有更好的办法?



Copyright 1998-2021. All rights reserved.
工信部备案:冀ICP备19032940号-1|公安部备案号:13020802000209