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



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

我的问题是:

  1. 因为我传递相同的Lua状态到Lua函数,这是安全的吗?难道它不需要某种保护吗?lua函数是从另一个头调用的,所以我猜它们可能是同时调用的。

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

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

有很多方法来处理这个问题。最流行的是某种形式的投票。

最近的通用同步库是DarkSideSync

到libbev的一个流行的Lua绑定是Lua -ev

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

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

    • 一旦一个连接线程需要调用一个Lua函数,它检查出一个Lua状态的实例,在一个单独的(代理)全局表中初始化特定的全局(我称之为线程/连接上下文),以防止污染原始全局,但被原始全局索引
    • 调用Lua函数
    • 将Lua状态检回到池中,在那里它被恢复到"就绪"状态(处置代理全局表)

我认为这种方法也很适合你的情况。池在最后签出时检查每个状态(以间隔为基础)。当时间差足够大时,它会破坏状态以保留资源,并根据当前服务器负载调整活动状态的数量。签出的状态是可用状态中最近使用的状态。

在实现这样一个池时需要考虑一些事情:

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

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

  1. 这是不安全的,因为其他人提到
  2. 取决于你的使用情况

最简单的解决方案是使用lua_locklua_unlock宏使用全局锁。这将使用单个Lua状态,由单个互斥锁锁定。对于低数量的回调,它可能足够了,但对于较高的流量,由于产生的开销,它可能不会。

当你需要更好的性能时,W.B.提到的Lua状态池是一个很好的解决方法。这里我发现最棘手的部分是跨多个状态同步全局数据。 Doug提到的

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

相关内容

最新更新