Lua in a threaded enviroment

classic Classic list List threaded Threaded
16 messages Options
Reply | Threaded
Open this post in threaded view
|

Lua in a threaded enviroment

Marc Balmer
Does someone on this list have experience with running Lua in a threaded environment?

I am thinking about the following scenario:

- A main thread creates a Lua state and uses it the usual way using the C API.
- A secondary thread should call a function in said Lua state from time to time,
asynchronously and not predictable when it will do so. Totally independent from
the main thread.

It's obvious that this will not work and that some sort of arbitration will be needed.  As
I understand, there is no locking at all in Lua, and not even a function to query if a
Lua state is currently executing Lua code, i.e. if another thread is running the Lua
interpreter.

What's the best approach to this?  I think I will have to add a locking mechanism
and aquire the lock before calling any of the Lua C API functions.  Are there better
ways?


Reply | Threaded
Open this post in threaded view
|

Re: Lua in a threaded enviroment

Daurnimator
On 28 August 2016 at 19:57, Marc Balmer <[hidden email]> wrote:

> Does someone on this list have experience with running Lua in a threaded environment?
>
> I am thinking about the following scenario:
>
> - A main thread creates a Lua state and uses it the usual way using the C API.
> - A secondary thread should call a function in said Lua state from time to time,
> asynchronously and not predictable when it will do so. Totally independent from
> the main thread.
>
> It's obvious that this will not work and that some sort of arbitration will be needed.  As
> I understand, there is no locking at all in Lua, and not even a function to query if a
> Lua state is currently executing Lua code, i.e. if another thread is running the Lua
> interpreter.
>
> What's the best approach to this?  I think I will have to add a locking mechanism
> and aquire the lock before calling any of the Lua C API functions.  Are there better
> ways?
>
>

Yes.

Alternatively, you can define lua_lock and lua_unlock to use some sort
of mutex (when you compile lua)

Reply | Threaded
Open this post in threaded view
|

Re: Lua in a threaded enviroment

Pedro Tammela
In reply to this post by Marc Balmer
On 28 August 2016 at 19:57, Marc Balmer <[hidden email]> wrote:
> Does someone on this list have experience with running Lua in a threaded environment?
>
> I am thinking about the following scenario:
>
> - A main thread creates a Lua state and uses it the usual way using the C API.
> - A secondary thread should call a function in said Lua state from time to time,
> asynchronously and not predictable when it will do so. Totally independent from
> the main thread.
>
> It's obvious that this will not work and that some sort of arbitration will be needed.  As
> I understand, there is no locking at all in Lua, and not even a function to query if a
> Lua state is currently executing Lua code, i.e. if another thread is running the Lua
> interpreter.
>
> What's the best approach to this?  I think I will have to add a locking mechanism
> and aquire the lock before calling any of the Lua C API functions.  Are there better
> ways?
>
>

There's a library called luaproc that creates worker threads using pthreads.
https://github.com/askyrme/luaproc
Reply | Threaded
Open this post in threaded view
|

Re: Lua in a threaded enviroment

Viacheslav Usov
In reply to this post by Marc Balmer
On Sun, Aug 28, 2016 at 11:57 AM, Marc Balmer <[hidden email]> wrote:

> What's the best approach to this?  I think I will have to add a locking mechanism and aquire the lock before calling any of the Lua C API functions.  Are there better ways?

As already explained, Lua can be recompiled so that it will use a lock when needed. An obvious drawback is that performance may suffer, but unless you measure that and find it significant, you cannot say for sure. Another drawback is that you will have to rely on a custom library, but this may be a non-issue for your project. 

In a particular project where I use Lua, we can have a large number of threads interacting with a large number of Lua environments. Our Lua is custom built, so we could have used the built-in lock option. But since we have just one point of interaction between the threads and the environments, it was easier to add synchronisation there.

I think I should also warn you against a particular danger when you "aquire the lock before calling any of the Lua C API functions". If there are any functions defined by your host, which are callable from within Lua environments, these functions should better not acquire the lock, or you risk running into a deadlock or trashing your lock if it is not recursive. In the approach we adopted in our project we have no such problem because there is just one well defined point interaction.

Cheers,
V.
Reply | Threaded
Open this post in threaded view
|

Re: Lua in a threaded enviroment

Victor Bombi

I use lualanes for that also getting inter-thread comunication
----- Original Message -----
Sent: Sunday, August 28, 2016 5:43 PM
Subject: Re: Lua in a threaded enviroment

On Sun, Aug 28, 2016 at 11:57 AM, Marc Balmer <[hidden email]> wrote:

> What's the best approach to this?  I think I will have to add a locking mechanism and aquire the lock before calling any of the Lua C API functions.  Are there better ways?

As already explained, Lua can be recompiled so that it will use a lock when needed. An obvious drawback is that performance may suffer, but unless you measure that and find it significant, you cannot say for sure. Another drawback is that you will have to rely on a custom library, but this may be a non-issue for your project. 

In a particular project where I use Lua, we can have a large number of threads interacting with a large number of Lua environments. Our Lua is custom built, so we could have used the built-in lock option. But since we have just one point of interaction between the threads and the environments, it was easier to add synchronisation there.

I think I should also warn you against a particular danger when you "aquire the lock before calling any of the Lua C API functions". If there are any functions defined by your host, which are callable from within Lua environments, these functions should better not acquire the lock, or you risk running into a deadlock or trashing your lock if it is not recursive. In the approach we adopted in our project we have no such problem because there is just one well defined point interaction.

Cheers,
V.
Reply | Threaded
Open this post in threaded view
|

Re: Lua in a threaded enviroment

Jerome Vuarand
In reply to this post by Marc Balmer
2016-08-28 10:57 GMT+01:00 Marc Balmer <[hidden email]>:

> Does someone on this list have experience with running Lua in a threaded environment?
>
> I am thinking about the following scenario:
>
> - A main thread creates a Lua state and uses it the usual way using the C API.
> - A secondary thread should call a function in said Lua state from time to time,
> asynchronously and not predictable when it will do so. Totally independent from
> the main thread.
>
> It's obvious that this will not work and that some sort of arbitration will be needed.  As
> I understand, there is no locking at all in Lua, and not even a function to query if a
> Lua state is currently executing Lua code, i.e. if another thread is running the Lua
> interpreter.
>
> What's the best approach to this?  I think I will have to add a locking mechanism
> and aquire the lock before calling any of the Lua C API functions.  Are there better
> ways?

As suggested by Daurnimator using lua_lock/lua_unlock is the way to go
(IMHO, assuming you can recompile Lua). However keep in mind that the
more code you run in Lua, the more delays will be introduced before
your asynchronous code is executed. In the worst (degenerate) case,
where the main thread only runs Lua code 100% of the time (think
"while true do end") then your asynchronous code will *never* be
executed.

If you really need preemption, then I think you should look at how
signal handling is done in the stock interpreter. It installs a one
time hook on call, return and count=1. I'm not sure how thread safe
that is, I can only guess it's safe enough to call from a signal
handler if the stock interpreter does it. But does that translate to
the kind of preemption you want to use?

Reply | Threaded
Open this post in threaded view
|

AW: Lua in a threaded enviroment

Eike Decker
In reply to this post by Marc Balmer

I am not sure if this would work, but you could try using the debug api to interrupt your lua state every n operations and check then a queue if there’s something waiting to get called.

 

Since the debug hook has then interrupted the lua program and is allowed to manipulate it, this might work. It would not work when the lua program is making long lasting native calls, of course...

 

 

Cheers

Eike

 

Gesendet von meinem Windows 10 Phone

 

Von: [hidden email]
Gesendet: Sonntag, 28. August 2016 11:57
An: [hidden email]
Betreff: Lua in a threaded enviroment

 

Does someone on this list have experience with running Lua in a threaded environment?

 

I am thinking about the following scenario:

 

- A main thread creates a Lua state and uses it the usual way using the C API.

- A secondary thread should call a function in said Lua state from time to time,

asynchronously and not predictable when it will do so. Totally independent from

the main thread.

 

It's obvious that this will not work and that some sort of arbitration will be needed.  As

I understand, there is no locking at all in Lua, and not even a function to query if a

Lua state is currently executing Lua code, i.e. if another thread is running the Lua

interpreter.

 

What's the best approach to this?  I think I will have to add a locking mechanism

and aquire the lock before calling any of the Lua C API functions.  Are there better

ways?

 

 

 

Reply | Threaded
Open this post in threaded view
|

Re: Lua in a threaded enviroment

Daurnimator
In reply to this post by Jerome Vuarand
On 30 August 2016 at 11:02, Jerome Vuarand <[hidden email]> wrote:
> If you really need preemption, then I think you should look at how
> signal handling is done in the stock interpreter. It installs a one
> time hook on call, return and count=1. I'm not sure how thread safe
> that is, I can only guess it's safe enough to call from a signal
> handler if the stock interpreter does it. But does that translate to
> the kind of preemption you want to use?

One of the more interesting things you can do here is inject a hook
that calls lua_yield.
This means your top level "lua_resume" (or lua_pcallk) will return,
and you can perform some operation before proceeding.

You need to know which coroutine is running; there is no safe way to
find this out.
Note that the official lua interpreter also suffers due to this,
Ctrl+C will *not* interrupt a coroutine:

$ lua
Lua 5.3.3  Copyright (C) 1994-2016 Lua.org, PUC-Rio
> while  true do end
^Cinterrupted!
stack traceback:
stdin:1: in main chunk
[C]: in ?
> coroutine.wrap(function() while true do end end)()
^C^C
$

Annoyingly you can't return any parameters from the lua_yield in a
debug hook. See http://lua-users.org/lists/lua-l/2015-12/msg00094.html

Reply | Threaded
Open this post in threaded view
|

Re: AW: Lua in a threaded enviroment

Laurent FAILLIE
In reply to this post by Eike Decker
Hello,

I found a way that is working for months now (after a long fight and some help form this mailing list :) ) : you can have a look on my application named Séléné (https://github.com/destroyedlolo/Selene/) which is a scripting automation tool driven by MQTT messages arrival.
It is used to drive my smart home automation as well to build a dashboard using DirectFB plug-in.

All user scripts are made in Lua whereas all the backend, technical layers, MQTT, DirectDB handling is made in C.

The main thread has it's own Lua_State which load the code and stores global stuffs (functions, ...).

Due to MQTT library design, each MQTT messages arrival is handled by a separated thread : in this new thread, I'm creating a new dedicated lua_State, and retrieving some information (like the function to call) from the main thread's state, protected by a mutex (the only moment I'm blocking the main thread).

All in all, I got several totally separated threads running in parallel.

They are exchanging data using shared object which are protected by dedicated mutex (so only 1 object is blocked during access), managed at C side.

Perhaps my explanation is not very clear, but I hope the corresponding code is quite understandable.

All in all, I'm very satisfied by this solution which is :
- safe
- efficient
- very easy to work with.


Bye

Laurent
Reply | Threaded
Open this post in threaded view
|

Re: Lua in a threaded enviroment

Thomas Jericke
In reply to this post by Marc Balmer
On 28.08.2016 11:57, Marc Balmer wrote:

> Does someone on this list have experience with running Lua in a threaded environment?
>
> I am thinking about the following scenario:
>
> - A main thread creates a Lua state and uses it the usual way using the C API.
> - A secondary thread should call a function in said Lua state from time to time,
> asynchronously and not predictable when it will do so. Totally independent from
> the main thread.
>
> It's obvious that this will not work and that some sort of arbitration will be needed.  As
> I understand, there is no locking at all in Lua, and not even a function to query if a
> Lua state is currently executing Lua code, i.e. if another thread is running the Lua
> interpreter.
>
> What's the best approach to this?  I think I will have to add a locking mechanism
> and aquire the lock before calling any of the Lua C API functions.  Are there better
> ways?
>
>
Our system has a similar scenario. We use a message driven approach to
solve multi-threading problems like this.
Instead of using locks over the Lua state, the Lua state 'belongs'
strictly to the main thread. If another thread want's to access
the Lua state, it passes a message to the main thread, which executes
the Lua function and passes the results back to the calling thread.

Now, as it has been said, it is important to know whether you need
preemptive scheduling or not. If you don't need preemptive scheduling
you can simply
make a main loop in you main thread that does nothing else but waiting
for work to do.
--

Thomas


Reply | Threaded
Open this post in threaded view
|

Re: Lua in a threaded enviroment

Thijs Schreijer
In reply to this post by Marc Balmer

On 28 Aug 2016, at 11:57, Marc Balmer <[hidden email]> wrote:

Does someone on this list have experience with running Lua in a threaded environment?

I am thinking about the following scenario:

- A main thread creates a Lua state and uses it the usual way using the C API.
- A secondary thread should call a function in said Lua state from time to time,
asynchronously and not predictable when it will do so. Totally independent from
the main thread.

It's obvious that this will not work and that some sort of arbitration will be needed.  As
I understand, there is no locking at all in Lua, and not even a function to query if a
Lua state is currently executing Lua code, i.e. if another thread is running the Lua
interpreter.

What's the best approach to this?  I think I will have to add a locking mechanism
and aquire the lock before calling any of the Lua C API functions.  Are there better
ways?



Already a while ago I specifically wrote a library [1] that can be used to signal incoming data from a background thread using sockets. I used it for a UPnP background process/thread and on a raspberry pi, to signal events from the GPIO interface [2] (also from a background thread).

generally combined with the Copas scheduler [3]

Thijs

Reply | Threaded
Open this post in threaded view
|

Re: Lua in a threaded enviroment

Russell Haley
In reply to this post by Marc Balmer
https://github.com/tnodir/luasys

This library can take advantage of Unix threads, domain sockets,
polling, events, kqueue and pretty much any other Unix C api that a
developer could want. Just don't expect anything from the author. I
was told in no uncertain terms this library is for those already
initiated in the ways of Unix C.

Russ

On Sun, Aug 28, 2016 at 2:57 AM, Marc Balmer <[hidden email]> wrote:

> Does someone on this list have experience with running Lua in a threaded environment?
>
> I am thinking about the following scenario:
>
> - A main thread creates a Lua state and uses it the usual way using the C API.
> - A secondary thread should call a function in said Lua state from time to time,
> asynchronously and not predictable when it will do so. Totally independent from
> the main thread.
>
> It's obvious that this will not work and that some sort of arbitration will be needed.  As
> I understand, there is no locking at all in Lua, and not even a function to query if a
> Lua state is currently executing Lua code, i.e. if another thread is running the Lua
> interpreter.
>
> What's the best approach to this?  I think I will have to add a locking mechanism
> and aquire the lock before calling any of the Lua C API functions.  Are there better
> ways?
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Lua in a threaded enviroment

Chris Jones
In reply to this post by Marc Balmer
Hey

Depending on your target platform, and since you can only ever have one thread executing Lua at a time, it may be easier to dispatch the work to happen on the main thread. We do this in Hammerspoon (OS X) using Apple's SDK (things like dispatch_sync(), dispatch_async() and [NSObject performSelectorOnMainThread]).

(For the sake of safety, we also perform a sanity check almost every time a C function is about to do some Lua work, to make sure it's happening on the main thread)

Cheers,
Chris

On 28 August 2016 at 11:57, Marc Balmer <[hidden email]> wrote:
Does someone on this list have experience with running Lua in a threaded environment?

I am thinking about the following scenario:

- A main thread creates a Lua state and uses it the usual way using the C API.
- A secondary thread should call a function in said Lua state from time to time,
asynchronously and not predictable when it will do so. Totally independent from
the main thread.

It's obvious that this will not work and that some sort of arbitration will be needed.  As
I understand, there is no locking at all in Lua, and not even a function to query if a
Lua state is currently executing Lua code, i.e. if another thread is running the Lua
interpreter.

What's the best approach to this?  I think I will have to add a locking mechanism
and aquire the lock before calling any of the Lua C API functions.  Are there better
ways?





--
Cheers,

Chris
Reply | Threaded
Open this post in threaded view
|

Re: Lua in a threaded enviroment

Daurnimator
On 31 August 2016 at 20:14, Chris Jones <[hidden email]> wrote:

> Hey
>
> Depending on your target platform, and since you can only ever have one
> thread executing Lua at a time, it may be easier to dispatch the work to
> happen on the main thread. We do this in Hammerspoon (OS X) using Apple's
> SDK (things like dispatch_sync(), dispatch_async() and [NSObject
> performSelectorOnMainThread]).
>
> (For the sake of safety, we also perform a sanity check almost every time a
> C function is about to do some Lua work, to make sure it's happening on the
> main thread)

(please bottom post on this list).

You might be interested in this post of mine:
http://daurnimator.com/post/147024385399/using-your-own-main-loop-on-osx

Gives you freedom from libdispatch's built in loop :)

Reply | Threaded
Open this post in threaded view
|

Re: Lua in a threaded enviroment

Rain Gloom
In reply to this post by Daurnimator
On Tue, Aug 30, 2016 at 7:20 AM, Daurnimator <[hidden email]> wrote:
One of the more interesting things you can do here is inject a hook
that calls lua_yield.
This means your top level "lua_resume" (or lua_pcallk) will return,
and you can perform some operation before proceeding.

Does this only work from C? I have tried a naive pure-Lua thread implementation with debug.sethook(coroutine.yield,'',1) and it blew up.
Reply | Threaded
Open this post in threaded view
|

Re: Lua in a threaded enviroment

nobody
On 2016-09-03 15:39, Rain Gloom wrote:

> On Tue, Aug 30, 2016 at 7:20 AM, Daurnimator <[hidden email]>
> wrote:
>
>> One of the more interesting things you can do here is inject a hook
>> that calls lua_yield. This means your top level "lua_resume" (or
>> lua_pcallk) will return, and you can perform some operation before
>> proceeding.
>
> Does this only work from C? I have tried a naive pure-Lua thread
> implementation with debug.sethook(coroutine.yield,'',1) and it blew
> up.

Yes.


`debug.sethook` sets a ready-made C hook function[1] that calls the hook
function set from Lua.  This means there's an extra C layer in the way
that you can't yield through.

The hook is not a normal Lua C function/closure, but a raw C function.
So the hook can't lua_[p]callk & then yield.


My accumulated "C API cheats" contain the following crappy workaround
which I use whenever I need this functionality in Lua ("soft"/resumable
timeouts mostly - I run into that quite often...):

static void yieldhook( lua_State * L, lua_Debug * ar ) {
        lua_yield( L, 0 );
}

/* setyieldhook( coro, [count=0] ) ~~> sethook( coro, nil ) */
/* setyieldhook( coro, count ) ~~> sethook( coro, yield, "", count ) */
static int lcheat_setyieldhook( lua_State * L ) {
        lua_State * coro;
        int steps;
        luaL_checktype( L, 1, LUA_TTHREAD );
        coro = lua_tothread( L, 1 );
        steps = luaL_optinteger( L, 2, 0 );
        if (steps <= 0) {
                lua_sethook( coro, NULL, 0, 0 );
        } else {
                lua_sethook( coro, yieldhook, LUA_MASKCOUNT, steps );
        }
        return 0;
}

It's a bit ugly...  One limitation is that it will only yield (and do
nothing else, not even return a special marker value from the yield).
You also can't `setyieldhook` and then clear it with `debug.sethook`.
(`debug.sethook`/`debug.gethook` store the hook info as an entry in the
registry with a userdata value as its key.  There may be several such
values, so it would be rather complex to identify the right one of those.)

It may still be enough or at least serve as a starting point.


[1]: https://www.lua.org/source/5.3/ldblib.c.html#hookf