从另一个线程调用lua函数(作为回调)足够安全吗?

时间:2013-05-16 02:34:59

标签: visual-c++ lua

实际上我正在使用visual C ++来尝试将lua函数绑定为套接字事件的回调(在另一个线程中)。我在一个线程中初始化lua的东西,而套接字在另一个线程中,所以每次套接字发送/接收消息时,它都会调用lua函数,而lua函数根据内部的'tag'确定它应该做什么。消息。

所以我的问题是:

  1. 由于我将相同的Lua状态传递给lua函数,这样安全吗?它不需要某种保护吗? lua函数是从另一个thead调用的,所以我猜他们可能会被同时调用。

  2. 如果不安全,这种情况的解决方案是什么?

3 个答案:

答案 0 :(得分:2)

异步回调到Lua状态是不安全的。

有很多方法可以解决这个问题。最受欢迎的是某种民意调查。

最近的通用同步库是DarkSideSync

与libev绑定的流行Lua是lua-ev

This SO answer推荐Lua Lanes和LuaSocket。

答案 1 :(得分:1)

  1. 在多个线程中同时调用一个Lua状态下的函数是不安全的。

  2. 我正在处理同样的问题,因为在我的应用程序中,所有基础知识(如通信)都由C ++处理,所有业务逻辑都在Lua中实现。我所做的是创建一个 Lua状态池,它们都是在增量的基础上创建和初始化的(一旦没有足够的状态,创建一个并使用公共函数/对象初始化)。它的工作原理如下:

    • 一旦连接线程需要调用Lua函数,它就会检出Lua状态的实例,在单独的(代理)全局表中初始化特定的全局变量(我称之为线程/连接上下文),以防止污染原始全局,但由原始全球
    • 索引
    • 调用Lua函数
    • 检查Lua状态,返回池中,恢复到“就绪”状态(处理代理全局表)
  3. 我认为这种方法也非常适合您的情况。池在上次检出时检查每个状态(以间隔为基础)。当时间差足够大时,它会破坏状态以保留资源并调整当前服务器负载的活动状态数。签出的状态是最近在可用状态中使用的状态。

    在实施这样的池时,您需要考虑一些事项:

    • 每个州都需要填充相同的变量和全局函数,这会增加内存消耗。
    • 实现池中状态计数的上限
    • 确保每个状态中的所有全局变量都处于一致状态,如果它们发生变化(这里我建议只预先填充静态全局变量,同时在检查状态时填充动态全局变量)
    • 动态加载功能。在我的例子中,可以在Lua中调用数千个函数/过程。让它们在所有州持续装载将是一个巨大的浪费。因此,我将它们保存在C ++端编译的字节代码,并在需要时加载它们。事实证明,在我的情况下不会影响性能,但您的里程可能会有所不同。要记住的一件事是只加载一次。假设你调用一个需要在循环中调用另一个动态加载函数的脚本。然后你应该在循环之前将函数加载为本地一次。否则,这将是一个巨大的性能损失。

    当然这只是一个想法,但结果最适合我。

答案 2 :(得分:1)

  1. 正如其他人提到的那样,这是不安全的
  2. 取决于您的用例
  3. 最简单的解决方案是使用lua_locklua_unlock宏进行全局锁定。这将使用由单个互斥锁锁定的单个Lua状态。对于少量的回调它可能就足够了,但是对于更高的流量,它可能不会由于产生的开销而产生。

    一旦你需要更好的性能,就像W.B.提到的Lua状态池。处理这个是一个很好的方法。这里最棘手的部分我发现在多个状态中同步全局数据。

    Doug提到的

    DarkSideSync在主应用程序循环驻留在Lua端的情况下非常有用。我专门为此目的写了它。在你的情况下,这似乎不合适。话说回来;根据您的需要,您可以考虑更改您的应用程序,以便主循环确实驻留在Lua端。如果只处理套接字,则可以使用LuaSocket,根本不需要同步。但显然这取决于应用程序的其他功能。