2

我正在编写一个 Lua 脚本,它使用一个库来访问带有按钮的硬件设备。我注册了一个回调函数来处理按钮按下。代码如下所示:

globalvar = {}

function buttonCallback(buttonId)
    ...accessing globalvar
end

device.RegisterButtonCallback("buttonCallback")

while true do
end

这行得通。

现在我想更新 globalvar 不仅在按钮按下,而且在 1 分钟间隔。因为无论如何我都需要访问网络资源,所以我计划使用 socket.select 调用来获得 1 分钟的间隔。

#require "socket"

globalvar = {}

function buttonCallback(buttonId)
    ...access globalvar
end

device.RegisterButtonCallback("buttonCallback")

while true do
    socket.select(nil, nil, 60)  -- wait 60 seconds
    ...access network
    ...access globalvar
end

现在我关心的是globalvar的并发访问。我怎样才能在这里防止比赛条件?Lua 中关于多线程的大多数资源都建议在协作调度中使用延续,但我不知道如何在我的案例中应用它。

4

3 回答 3

2

假设您正在使用的库正在幕后创建另一个线程,并且您唯一关心的是从回调中访问,您可以通过在回调中写入管道并在循环globalvar中读取它来避免它。select换句话说,使用标准 POSIX 风格的管道将回调传回主线程。在处理例如 POSIX 信号时,这是一种相当常见的技术。

于 2013-02-13T13:53:31.257 回答
2

Lua 在特定lua_State实例中不是线程安全的。当另一个线程对该 Lua 实例执行其他操作时,您不能从一个线程修改全局变量。您当然不能在同一个实例上执行两个单独的脚本。

线程安全是你必须在 Lua 之外做的事情。您不能让检测按钮按下的 C/C++ 线程实际直接调用 Lua 代码。它必须通过某种线程安全机制将该数据发送到主线程,在那里它将为它们调用 Lua 脚本。

于 2013-02-13T20:31:32.560 回答
0

于是我深入研究了 Lua 书籍和在线文档,并联系了设备驱动的作者。正如答案已经表明的那样,安全处理按钮回调需要比预期更多的时间。

我现在的方法是自己编写设备驱动程序,并使用套接字作为设备和 Lua 脚本之间的通信通道。

我最初的方法是使用延续,因为这被提倡作为多线程的 Lua“替代品”,但是当我阅读 Lua 书中的编程时,事实证明,为了防止忙等待,它使用了 socket.select(!)。这增加了我对基于套接字的方法很好的感觉,特别是因为我的脚本中还需要用于 Internet 访问的套接字。

于 2013-03-11T21:04:58.003 回答