lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

Am Mo., 27. Feb. 2023 um 03:58 Uhr schrieb Frank Mitchell
> Sorry for any confusion. My mail service was dumping most of the Lua-L list into a spam folder
Thank you for your hint, I now finally discovered your posts in my
Gmail spam folder... .

> As you said, it's important not to spawn more threads than the machine has cores, otherwise the extra >threads will only reduce throughput.

This is misunderstanding I am frightened. My STM32 machine HAS only
one core. Just MANY STM32 are communicating with each other in my
system (so you could "theoretically" speak of MANY cores, with Lua
running on each core).

I did not think so far, what I would do / recommend if I would program
a multi-core system. But from my experience with
multi-core-multi-threading on Windows PC, I would quite sure NOT run
Lua on more than one core, and use the other cores only for some "C
subtasks" which are not really presented to the Lua users during
"subtask run time" (so the Lua User would get the results only, and
communicate only through the ONE Lua State in ONE "Lua-core"). (I used
multi-core-multithreading already in a Windows Software to speed up
communications, for this purpose of course nice somehow, but also very
tricky to be sure about data integrity, also debugging if you do any
changes after longer time again...).

Maybe it is helpful for you, if I just describe a bit, how my task system runs:
- Any STM32 CPU with Lua has a C main loop, and further also the Lua
program running has a "Lua main loop".

- Only one Lua base state, which is used as "mother state" for all
threads. Only the threads resume-yield / do the "Lua work".
- if a user wants to create a new task, he can do with "
confstring, runfunction, ...)",  (... are the function pars, e. g. '', print, 'hallo') ). The conf string can be used for conf
settings: Speed of the task (max speed (resume in any loop of my CPU
main loop) or resume only 512 / 256 / 128/ ... 1 time per second...).
Every task is a new Lua Thread, defined as userdata. Each such
userdata pointer is saved in the registry with a unique name (so that
it can NOT be killed by GC). If the 'runfunction' of the task is
terminated, resume will return LUA_OK, and then the thread will be
killed with lua_resetthread and the registry entry for the userdata
will be set to nil (so that the GC can kill this userdata).
- communication between the tasks is quite straight forward, as all
tasks / Lua threads are based on ONE lua state, so they share a common
global table - the Lua user can use global variables for exchanging
data between the tasks... .

My task system further allows, that other STM32 CPUs send some Lua
command string through communication channel. At first I thought, that
I can run such "communicated Lua commands" in the LuaBase state. But
this will work only for very simple and direct Lua commands (like e.
g. 'A=A+1' or so - with problems appearing already, when I want to
handle "command string errors", and also if I want to use lua_pcallk,
which is very important for more complicated Lua commands which
require yielding - this can NOT be invoked from Lua Base state, but
only inside a running / resumed Lua thread).

So I finally decided, that I present a sort of "luaexecute" function
to the Lua user. And this "luaexecute" MUST be run continuously in the
Lua Main Loop. This is job of the Lua user to ensure this. (if the Lua
user does NOT invoke the "luaexecute" function in his Lua main loop,
then such "Lua commands communicated from other STM32 controllers" are
ignored / NOT handled (this IS nice btw. for Lua debugging purpose
sometimes, to enusre that the "Lua process flow" is NOT disturbed by
extrenal events...).

So generally, I use exactly the Lua thread handling as described in
Roberto's ingenious "Programming in Lua" book at the very end (Chapter
33 - page 288, "8" being chinese lucky number by the way :) ). Just
the following 2-3 "tricks" are very important for my task system:
- create some userdata for every thread (= every object which I call "task")
- keep the userdata pointer in registry during runtime to protect
against GC (by default after lua_newthread it will be on Lua Base
State STACK - this also protects against GC, but you then get of
course slight problems, if you want to kill the threads again after
end of runtime).
- define a function like "luaexecute" which the Lua User MUST invoke
in regular intervals (in his Lua main loop), and do all the checking
for "externally communicated Lua command strings" in this luaexecute
(as you are then running inside the main loop, it is no problem to use

... hope this helps, sorry for the long post... .