LuaPlus - Delay/Sleep function

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • LuaPlus - Delay/Sleep function

      Hello!

      I am trying to implement a function for the scriptable part of my engine that would allow to make a Lua procedure wait a given amount of seconds before it can proceed with further execution. The function should only block the Lua code (running in its own thread) and not the main game loop.

      An example usage would be as follows:

      Source Code

      1. repeat
      2. wait(2)
      3. until actor.isReady


      Any ideas how such function could be implemented? So far I've been playing around with Windows' Sleep() function but couldn't make it execute on the Lua thread, thus it was blocking my entire program.

      Any advice will be appreciated.

      The post was edited 3 times, last by xor ().

    • I'm unsure why you would want to do it this way, but if you are really wanting this, you could simply do a while loop until a given duration has passed.
      PC - Custom Built
      CPU: 3rd Gen. Intel i7 3770 3.4Ghz
      GPU: ATI Radeon HD 7959 3GB
      RAM: 16GB

      Laptop - Alienware M17x
      CPU: 3rd Gen. Intel i7 - Ivy Bridge
      GPU: NVIDIA GeForce GTX 660M - 2GB GDDR5
      RAM: 8GB Dual Channel DDR3 @ 1600mhz
    • Originally posted by mholley519
      I'm unsure why you would want to do it this way

      That's why I'm asking for ideas. I'm using Lua without the standard library that would provide me with functions for accessing time etc., so I need to implement them myself.

      Originally posted by mholley519
      but if you are really wanting this, you could simply do a while loop until a given duration has passed.

      How? I cannot use the standard Lua functions for accessing the OS time.

      Anyway, I think I came up with a better solution. I might just pause the Lua global state for a given amount of time (passed to the wait() function) and run the counter as a process in the main loop (in C++) that would be updating the clock every tick. When the counter hits zero, the global Lua state would be resumed again. None of it will be blocking the main thread, while still providing the ability to delay the code execution on the Lua side.

      The post was edited 1 time, last by xor ().

    • Sorry, what I meant was why you would want to block your Lua function?

      Also is there a reason you can't use the Lua standard libs?
      PC - Custom Built
      CPU: 3rd Gen. Intel i7 3770 3.4Ghz
      GPU: ATI Radeon HD 7959 3GB
      RAM: 16GB

      Laptop - Alienware M17x
      CPU: 3rd Gen. Intel i7 - Ivy Bridge
      GPU: NVIDIA GeForce GTX 660M - 2GB GDDR5
      RAM: 8GB Dual Channel DDR3 @ 1600mhz
    • Originally posted by mholley519
      Also is there a reason you can't use the Lua standard libs?

      So far all my attempts to include the standard library in LuaPlus have been giving me strange linking problems. Other than that, I don't really have any reason to use the standard library, aside from perhaps accessing the OS time.

      Originally posted by rezination
      What is the problem you're trying to solve?

      -Rez

      I want to implement a function that will halt the execution of next Lua statements until a certain time has passed.

      For example something like this:

      Source Code

      1. repeat
      2. -- Waits 2 seconds.
      3. wait(2)
      4. until actor:isIdle()
      5. -- Continue when actor is idle.
    • Are you using the LuaPlus::LuaState::OpenLibs? Also if that isn't working for you, try to get the lua_State from you'r LuaPlus::LuaState, and call 'luaL_openlibs(m_pLuaState);'

      I only keep LuaPlus exposed in a single file for exporting functions, where the rest of my code is generic Lua C, so I am using the straight 'luaL_openlibs' and it works fine for me.
      PC - Custom Built
      CPU: 3rd Gen. Intel i7 3770 3.4Ghz
      GPU: ATI Radeon HD 7959 3GB
      RAM: 16GB

      Laptop - Alienware M17x
      CPU: 3rd Gen. Intel i7 - Ivy Bridge
      GPU: NVIDIA GeForce GTX 660M - 2GB GDDR5
      RAM: 8GB Dual Channel DDR3 @ 1600mhz

      The post was edited 1 time, last by mholley519 ().

    • Alright, I recompiled LuaPlus and I no longer receive linking problems when trying to call OpenLibs().

      I'm not sure how this would help though. Is there any Lua-side solution to pause the execution of the Lua code only, while still allowing the main loop (in C++) to run? So far, all the methods I found on the Internet halt the entire program (i.e. using the OS library).

      I still lean towards the idea of just pausing the Lua state altogether for a given duration and resuming it after the counter hits 0. I'm currently trying it out with Yield_() and Resume() functions but with no success so far.
    • I wouldn't use the system sleep as that would put the entire program to sleep, like I was saying before, now that you have access to the lua 'time', you could make your own sleep function that loops until the specified time is elapsed. I'm not sure that Lua has anything like a mutex so this will have to do.

      Out of curiosity though, what specifically do you need this for? Maybe the solution to your problem is the wrong way to go, let us know what you're trying to do and maybe we could find a different approach to it.
      PC - Custom Built
      CPU: 3rd Gen. Intel i7 3770 3.4Ghz
      GPU: ATI Radeon HD 7959 3GB
      RAM: 16GB

      Laptop - Alienware M17x
      CPU: 3rd Gen. Intel i7 - Ivy Bridge
      GPU: NVIDIA GeForce GTX 660M - 2GB GDDR5
      RAM: 8GB Dual Channel DDR3 @ 1600mhz
    • Originally posted by mholley519
      I wouldn't use the system sleep as that would put the entire program to sleep, like I was saying before, now that you have access to the lua 'time', you could make your own sleep function that loops until the specified time is elapsed. I'm not sure that Lua has anything like a mutex so this will have to do.

      I appreciate your help. Your approach, however, can potentially be taking up almost 100% of CPU. Calling os.time on every CPU cycle wouldn't be too optimal.

      Originally posted by mholley519
      Out of curiosity though, what specifically do you need this for? Maybe the solution to your problem is the wrong way to go, let us know what you're trying to do and maybe we could find a different approach to it.

      As I said, I would like a simple wait/delay function that only stops the Lua code, while the engine itself is still running. For example, while iterating through the "repeat-until" loop I would want the code to wait 2 seconds before testing the condition again.

      The post was edited 1 time, last by xor ().

    • Your approach, however, can potentially be taking up almost 100% of CPU. Calling os.time on every CPU cycle wouldn't be too optimal.


      No it wouldn't be at all, like I said Lua doesn't have anything really built in to Lua that can do this. This is somewhat of a different example, but try doing this in Javascript, there isn't a 'sleep' function in Javascript as it is a different way of programming, if you try to force it, the browser will just lock up, likewise scripting in Lua shouldn't necessarily be handled the way you would handle the same problem in C++.

      However, if you REALLY want to do this (and again I can't see any practical use case that couldn't be handled in a different, better way), you could always create a C function and export it to Lua for use, the C function might use STL thread or something to yield for a given time, and than return out of the function, and continue on with your Lua function. The cost of calling the C function shouldn't be of concern to you since you are already halting the execution as it is. Again though, maybe your approach to the problem you are trying to solve is the wrong angle.
      PC - Custom Built
      CPU: 3rd Gen. Intel i7 3770 3.4Ghz
      GPU: ATI Radeon HD 7959 3GB
      RAM: 16GB

      Laptop - Alienware M17x
      CPU: 3rd Gen. Intel i7 - Ivy Bridge
      GPU: NVIDIA GeForce GTX 660M - 2GB GDDR5
      RAM: 8GB Dual Channel DDR3 @ 1600mhz
    • Originally posted by mholley519
      No it wouldn't be at all, like I said Lua doesn't have anything really built in to Lua that can do this.

      Did you try it?

      I just tested the following piece of code to try waiting for 15 seconds:

      Source Code

      1. function sleep()
      2. time = os.clock()
      3. while os.clock() - time < 15 do end
      4. end

      And it spikes the CPU usage of my game from ~2% to ~18% and that's running on i7, so I would imagine it would be worse on older CPUs. Apart from that, because of the loop, the entire application stops being responsive, so there's also that.

      Originally posted by mholley519
      However, if you REALLY want to do this (and again I can't see any practical use case that couldn't be handled in a different, better way)

      What would be the better way?

      Originally posted by mholley519
      Again though, maybe your approach to the problem you are trying to solve is the wrong angle.

      The wait() function that blocks the code seems to be a quite common thing people want to implement over at game dev forums. I've seen such a function myself in one of the commercial RTS games and it was really useful, so I wouldn't necessarily say that my approach is wrong - but if you know a better solution I'm open to ideas.

      Originally posted by mholley519
      you could always create a C function and export it to Lua for use, the C function might use STL thread or something to yield for a given time, and than return out of the function, and continue on with your Lua function.

      How do I exactly export a C function that returns immediately from the C++ side, so the engine can keep running, while making the Lua code wait?
    • I meant the function WOULD be inefficient.

      Apart from that, because of the loop, the entire application stops being responsive


      Something is wrong with your threaded update of your scripting, it's hard to tell without taking a look, but if a call from your Lua thread is blocking your main thread something else is going on here.

      What would be the better way?


      This is case dependant, I meant more so that whatever situation your coming to that requires you to completely halt the execution of a Lua function may have a different approach such as not even calling the Lua function in the first place until the code is ready, if you require Lua code to halt while something else takes over, you may want to try co-routines which would at least allow for the most throughput of your Lua thread rather than simply waiting completely.

      but if you know a better solution I'm open to ideas


      Again, you haven't really given a clear usage case of why you would need this so I can't really give you a solution.

      How do I exactly export a C function that returns immediately from the C++ side, so the engine can keep running, while making the Lua code wait?


      You can either bind a C function using the Lua C API, or you can use something like LuaPlus mentioned in the chapter on scripting with Lua to bind the function. Once bound, simply calling it from Lua will call the C function and the Lua will not proceed until the C function has returned.
      PC - Custom Built
      CPU: 3rd Gen. Intel i7 3770 3.4Ghz
      GPU: ATI Radeon HD 7959 3GB
      RAM: 16GB

      Laptop - Alienware M17x
      CPU: 3rd Gen. Intel i7 - Ivy Bridge
      GPU: NVIDIA GeForce GTX 660M - 2GB GDDR5
      RAM: 8GB Dual Channel DDR3 @ 1600mhz
    • Originally posted by xor
      Originally posted by rezination
      What is the problem you're trying to solve?

      -Rez

      I want to implement a function that will halt the execution of next Lua statements until a certain time has passed.

      For example something like this:

      Source Code

      1. repeat
      2. -- Waits 2 seconds.
      3. wait(2)
      4. until actor:isIdle()
      5. -- Continue when actor is idle.


      Sorry for not being more clear. What you're describing is a programming solution. I'm asking for the problem you're trying to solve. For example, is your goal to have an alarm system so you can say "run this code in 2 seconds"? Are you trying to set up something so you can write an update function like this?:

      Source Code

      1. function Actor:Update()
      2. PathToLocation();
      3. RunAnimation();
      4. end


      In other words, are you trying to set it up so you don't have to care about timing at all and can just trust that things will run and yield as appropriate?

      If not, are you trying to set it up so you can tick the script once a second or so?

      Maybe a better question is what are your use cases? It might seem like I'm harping on this, but my answer will be highly dependent on your answer.

      My guess is that you're effectively trying to wait until until an actor is idle so you can process them again, but you don't want to do a busy-wait. That's good, but I think you're going about it the wrong way. All you're really doing here is a delayed busy-wait. You're probably going to call isIdle() many times more than necessary and you might sleep for almost 2 seconds once the actor is idle, which won't look very good.

      A better solution would be to use events. Rather than sleep the entire Lua thread (which means you can't run any other lua code on the same state), why not just register for an "actor is idle" event? That way you don't need to have that code at all, you just wait until you get the event. It's the best of both worlds; you process the actor as soon as possible and you're not wasting time testing the actor:isIdle() call.

      In my own engine, I built a whole action system that manages this relationship for me. Lua never gets an update function; it only responds to events. Anything that needs to be done over multiple frames does it with a C++ process that the Lua ActionState object spins up. Once it's done, it calls back into the action to say that it's done and the action continues processing. It sounds like you want something similar.

      -Rez
    • Originally posted by rezination
      Sorry for not being more clear. What you're describing is a programming solution. I'm asking for the problem you're trying to solve. For example, is your goal to have an alarm system so you can say "run this code in 2 seconds"? Are you trying to set up something so you can write an update function like this?:

      Source Code

      1. function Actor:Update()
      2. PathToLocation();
      3. RunAnimation();
      4. end


      No problem, perhaps I should have elaborated more on what I wanted to achieve. By the way, thanks for your time, I know the industry may be busy now with crunching (isn't first half of the year the crunching season for many companies?), so I definitely appreciate your input in this topic :)

      Originally posted by rezination
      My guess is that you're effectively trying to wait until until an actor is idle so you can process them again, but you don't want to do a busy-wait. That's good, but I think you're going about it the wrong way. All you're really doing here is a delayed busy-wait. You're probably going to call isIdle() many times more than necessary and you might sleep for almost 2 seconds once the actor is idle, which won't look very good.

      A better solution would be to use events. Rather than sleep the entire Lua thread (which means you can't run any other lua code on the same state), why not just register for an "actor is idle" event? That way you don't need to have that code at all, you just wait until you get the event. It's the best of both worlds; you process the actor as soon as possible and you're not wasting time testing the actor:isIdle() call.

      I am already using events and I can set a callback easily, by calling:

      Source Code

      1. Entity:onIdling(
      2. function(self, event)
      3. -- callback goes here
      4. end
      5. )

      So yes, that's already working in my engine. What I wanted besides of this, however, was to be able also to do some simple repeat-until loops for one-time use only, without the need to register lots of callbacks all over the code (at some point it becomes difficult to mantain all of that, especially if I'm scripting a long quest for a game - jumping all over the code, looking for callbacks, each with different "if" statement (for different quests) makes it look much more cryptic and more error-prone after a while).

      So in short, my wait() function is to be used for things such as scripted cutscenes or one-time quests - for anything else, I'm already using events :)


      ANYWAY,

      I have finally managed to implement what I wanted:
      - it doesn't require additional threads
      - it doesn't block the main thread
      - it doesn't spike up the CPU (in fact it makes the CPU use less resources)
      - it integrates nicely to Lua with just a one function call

      So in case anyone will have the same problem in the future, here is a brief description of how I implemented it:
      1. When executing Lua scripts, use LoadBuffer() - don't execute it right away.
      2. After the loading is complete, execute the script using Resume().
      3. Every time you want to pause Lua state (so it can wait before proceeding with the next statement) call a C function from Lua which returns the value of that state's Yield_() method.
      4. Once a given time has passed (there are different ways to implement it, I just created a WaitProcess that is updated every tick). Simply call Resume() again on that state.

      Voila! The Lua state continues its execution without a problem :)

      The post was edited 1 time, last by xor ().

    • Glad you got it working! In case you're curious, what you just implemented was a Lua coroutine. Google it if you're curious to learn more. :)

      -Rez
    • Yes, that's exactly what I wanted. I learned the concept of Lua coroutines while trying to solve that problem, so I thought that having a coroutine-like behavior implemented in C would be the way to go for implementing the wait() function.

      The post was edited 1 time, last by xor ().