相关文章推荐
任性的斑马  ·  Java org apache-阿里云·  8 月前    · 
失眠的猕猴桃  ·  在Intellij ...·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

Actually I am using visual C++ to try to bind lua functions as callbacks for socket events(in another thread). I initialize the lua stuff in one thread and the socket is in another thread, so every time the socket sends/receives a message, it will call the lua function and the lua function determines what it should do according to the 'tag' within the message.

So my questions are:

  • Since I pass the same Lua state to lua functions, is that safe? Doesn't it need some kinda protection? The lua functions are called from another thead so I guess they might be called simultaneously.

  • If it is not safe, what's the solution for this case?

  • It is not safe to call back asynchronously into a Lua state.

    There are many approaches to dealing with this. The most popular involve some kind of polling.

    A recent generic synchronization library is DarkSideSync

    A popular Lua binding to libev is lua-ev

    This SO answer recommends Lua Lanes with LuaSocket.

    Could you please explain the difference between Luan Lanes and DarkSideSync? DarkSideSync has little examples and I don't know how to use DarkSideSync Mickey Shine May 16, 2013 at 8:31 Lanes provides a data type, Lindas, that may be shared safely between Lanes, asynchronous Lua states. DarkSideSync is more focused on notification and communication between Lua and asynchronous C libraries. Doug Currie May 16, 2013 at 16:01 So if I have a single callback in a Lua script wrapped in mutexes in a C library, it's not safe to periodically call it from C? Daniel Oct 11, 2021 at 23:10
  • It is not safe to call function within one Lua state simultaneously in multiple threads.

  • I was dealing with the same problem, since in my application all basics such as communication are handled by C++ and all the business logic is implemented in Lua. What I do is create a pool of Lua states that are all created and initialised on an incremental basis (once there's not enough states, create one and initialise with common functions / objects). It works like this:

  • Once a connection thread needs to call a Lua function, it checks out an instance of Lua state, initialises specific globals (I call it a thread / connection context) in a separate (proxy) global table that prevents polluting the original global, but is indexed by the original global
  • Call a Lua function
  • Check the Lua state back in to the pool, where it is restored to the "ready" state (dispose of the proxy global table)
  • I think this approach would be well suited for your case as well. The pool checks each state (on an interval basis) when it was last checked out. When the time difference is big enough, it destroys the state to preserve resources and adjust the number of active states to current server load. The state that is checked out is the most recently used among the available states.

    There are some things you need to consider when implementing such a pool:

  • Each state needs to be populated with the same variables and global functions, which increases memory consumption.
  • Implementing an upper limit for state count in the pool
  • Ensuring all the globals in each state are in a consistent state, if they happen to change (here I would recommend prepopulating only static globals, while populating dynamic ones when checking out a state)
  • Dynamic loading of functions. In my case there are many thousands of functions / procedures that can be called in Lua. Having them constantly loaded in all states would be a huge waste. So instead I keep them byte code compiled on the C++ side and have them loaded when needed. It turns out not to impact performance that much in my case, but your mileage may vary. One thing to keep in mind is to load them only once. Say you invoke a script that needs to call another dynamically loaded function in a loop. Then you should load the function as a local once before the loop. Doing it otherwise would be a huge performance hit.
  • Of course this is just one idea, but one that turned out to be best suited for me.

    @MickeyShine - I can't give you anything that's realted to Lua, but you could have a look at mysql++ implementation of connection pools, which works more or less the sames way. Connection Pool W.B. May 16, 2013 at 8:32 What about calling a Lua state from different threads but in a synchronized way by wrapping calls in mutexes? Is that safe? Daniel Oct 11, 2021 at 23:12

    Simplest solution is using a global lock using the lua_lock and lua_unlock macros. That would use a single Lua state, locked by a single mutex. For a low number of callbacks it might suffice, but for higher traffic it probably won't due to the overhead incurred.

    Once you need better performance, the Lua state pool as mentioned by W.B. is a nice way to handle this. Trickiest part here I find synchronizing the global data across the multiple states.

    DarkSideSync , mentioned by Doug, is useful in cases where the main application loop resides on the Lua side. I specifically wrote it for that purpose. In your case this doesn't seem a fit. Having said that; depending on your needs, you might consider changing your application so the main loop does reside on the Lua side. If you only handle sockets, then you can use LuaSocket and no synchronization is required at all. But obviously that depends on what else the application does.

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question . Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers .