37

I cant figure out how to get lua to do any common timing tricks, such as

  • sleep - stop all action on thread

  • pause/wait - don't go on to the next command, but allow other code in the application to continue

  • block - don't go on to next command until the current one returns

And I've read that a

while os.clock()<time_point do 
--nothing
end

eats up CPU time.

Any suggestions? Is there an API call I'm missing?

UPDATE: I wrote this question a long time ago trying to get WOW Lua to replay actions on a schedule (i.e. stand, wait 1 sec, dance, wait 2 sec, sit. Without pauses, these happen almost all in the same quarter second.) As it turned out WOW had purposely disabled pretty much everything that allows doing action on a clock because it could break the game or enable bots. I figured to re-create a clock once it had been taken away, I'd have to do something crazy like create a work array (with an action and execution time) and then register an event handler on a bunch of common events, like mouse move, then in the even handler, process any action whose time had come. The event handler wouldn't actually happen every X milliseconds, but if it was happening every 2-100 ms, it would be close enough. Sadly I never tried it.

Community
  • 1
  • 1
MatthewMartin
  • 32,326
  • 33
  • 105
  • 164

20 Answers20

24

[I was going to post this as a comment on John Cromartie's post, but didn't realize you couldn't use formatting in a comment.]

I agree. Dropping it to a shell with os.execute() will definitely work but in general making shell calls is expensive. Wrapping some C code will be much quicker at run-time. In C/C++ on a Linux system, you could use:

static int lua_sleep(lua_State *L)
{
    int m = static_cast<int> (luaL_checknumber(L,1));
    usleep(m * 1000); 
    // usleep takes microseconds. This converts the parameter to milliseconds. 
    // Change this as necessary. 
    // Alternatively, use 'sleep()' to treat the parameter as whole seconds. 
    return 0;
}

Then, in main, do:

lua_pushcfunction(L, lua_sleep);
lua_setglobal(L, "sleep");

where "L" is your lua_State. Then, in your Lua script called from C/C++, you can use your function by calling:

sleep(1000) -- Sleeps for one second
Community
  • 1
  • 1
zslayton
  • 51,416
  • 9
  • 35
  • 50
19

If you happen to use LuaSocket in your project, or just have it installed and don't mind to use it, you can use the socket.sleep(time) function which sleeps for a given amount of time (in seconds).

This works both on Windows and Unix, and you do not have to compile additional modules.

I should add that the function supports fractional seconds as a parameter, i.e. socket.sleep(0.5) will sleep half a second. It uses Sleep() on Windows and nanosleep() elsewhere, so you may have issues with Windows accuracy when time gets too low.

Michal Kottman
  • 16,375
  • 3
  • 47
  • 62
10

You can't do it in pure Lua without eating CPU, but there's a simple, non-portable way:

os.execute("sleep 1")

(it will block)

Obviously, this only works on operating systems for which "sleep 1" is a valid command, for instance Unix, but not Windows.

Community
  • 1
  • 1
Kknd
  • 3,033
  • 26
  • 29
  • Note that on some systems where this works (e.g. OS X) this will not cause `os.clock()` to advance, since CPU time is not consumed. – Phrogz Apr 17 '14 at 03:25
9

Sleep Function - Usage : sleep(1) -- sleeps for 1 second

local clock = os.clock
function sleep(n)  -- seconds
   local t0 = clock()
   while clock() - t0 <= n do
   end
end

Pause Function - Usage : pause() -- pause and waits for the Return key

function pause()
   io.stdin:read'*l'
end

hope, this is what you needed! :D - Joe DF

Joe DF
  • 5,438
  • 6
  • 41
  • 63
8

for windows you can do this:

os.execute("CHOICE /n /d:y /c:yn /t:5")
musefan
  • 47,875
  • 21
  • 135
  • 185
Dave
  • 81
  • 1
  • 2
6

It doesn't get easier than this. Sleep might be implemented in your FLTK or whatever, but this covers all the best ways to do standard sort of system sleeps without special event interrupts. Behold:

-- we "pcall" (try/catch) the "ex", which had better include os.sleep
-- it may be a part of the standard library in future Lua versions (past 5.2)
local ok,ex = pcall(require,"ex")
if ok then
   -- print("Ex")
   -- we need a hack now too? ex.install(), you say? okay
   pcall(ex.install)
   -- let's try something else. why not?
   if ex.sleep and not os.sleep then os.sleep = ex.sleep end
end

if not os.sleep then
   -- we make os.sleep
   -- first by trying ffi, which is part of LuaJIT, which lets us write C code
   local ok,ffi = pcall(require,"ffi")
   if ok then
      -- print("FFI")
      -- we can use FFI
      -- let's just check one more time to make sure we still don't have os.sleep
      if not os.sleep then
         -- okay, here is our custom C sleep code:
         ffi.cdef[[
            void Sleep(int ms);
            int poll(struct pollfd *fds,unsigned long nfds,int timeout);
         ]]
         if ffi.os == "Windows" then
            os.sleep = function(sec)
               ffi.C.Sleep(sec*1000)
            end
         else
            os.sleep = function(sec)
               ffi.C.poll(nil,0,sec*1000)
            end
         end
      end
   else
      -- if we can't use FFI, we try LuaSocket, which is just called "socket"
      -- I'm 99.99999999% sure of that
      local ok,socket = pcall(require,"socket")
      -- ...but I'm not 100% sure of that
      if not ok then local ok,socket = pcall(require,"luasocket") end
      -- so if we're really using socket...
      if ok then
         -- print("Socket")
         -- we might as well confirm there still is no os.sleep
         if not os.sleep then
            -- our custom socket.select to os.sleep code:
            os.sleep = function(sec)
               socket.select(nil,nil,sec)
            end
         end
      else
         -- now we're going to test "alien"
         local ok,alien = pcall(require,"alien")
         if ok then
         -- print("Alien")
         -- beam me up...
            if not os.sleep then
               -- if we still don't have os.sleep, that is
               -- now, I don't know what the hell the following code does
               if alien.platform == "windows" then
                  kernel32 = alien.load("kernel32.dll")
                  local slep = kernel32.Sleep
                  slep:types{ret="void",abi="stdcall","uint"}
                  os.sleep = function(sec)
                     slep(sec*1000)
                  end
               else
                  local pol = alien.default.poll
                  pol:types('struct', 'unsigned long', 'int')
                  os.sleep = function(sec)
                     pol(nil,0,sec*1000)
                  end
               end
            end
         elseif package.config:match("^\\") then
            -- print("busywait")
            -- if the computer is politically opposed to NIXon, we do the busywait
            -- and shake it all about
            os.sleep = function(sec)
               local timr = os.time()
               repeat until os.time() > timr + sec
            end
         else
            -- print("NIX")
            -- or we get NIXed
            os.sleep = function(sec)
               os.execute("sleep " .. sec)
            end
         end
      end
   end
end
Fluff
  • 61
  • 1
  • 2
4

For the second request, pause/wait, where you stop processing in Lua and continue to run your application, you need coroutines. You end up with some C code like this following:

Lthread=lua_newthread(L);
luaL_loadfile(Lthread, file);
while ((status=lua_resume(Lthread, 0) == LUA_YIELD) {
  /* do some C code here */
}

and in Lua, you have the following:

function try_pause (func, param)
  local rc=func(param)
  while rc == false do
    coroutine.yield()
    rc=func(param)
  end
end

function is_data_ready (data)
  local rc=true
  -- check if data is ready, update rc to false if not ready
  return rc
end

try_pause(is_data_ready, data)
BMitch
  • 231,797
  • 42
  • 475
  • 450
3

I would implement a simple function to wrap the host system's sleep function in C.

John Cromartie
  • 4,184
  • 27
  • 32
3

Pure Lua uses only what is in ANSI standard C. Luiz Figuereido's lposix module contains much of what you need to do more systemsy things.

Norman Ramsey
  • 198,648
  • 61
  • 360
  • 533
3
require 'alien'

if alien.platform == "windows" then
  kernel32 = alien.load("kernel32.dll")
  sleep = kernel32.Sleep
  sleep:types{ret="void",abi="stdcall","uint"}
else
  -- untested !!!
  libc = alien.default
  local usleep = libc.usleep
  usleep:types('int', 'uint')
  sleep = function(ms)
    while ms > 1000 do
      usleep(1000)
      ms = ms - 1000
    end
    usleep(1000 * ms)
  end
end 

print('hello')
sleep(500)  -- sleep 500 ms
print('world')
avo
  • 31
  • 1
2

I agree with John on wrapping the sleep function. You could also use this wrapped sleep function to implement a pause function in lua (which would simply sleep then check to see if a certain condition has changed every so often). An alternative is to use hooks.

I'm not exactly sure what you mean with your third bulletpoint (don't commands usually complete before the next is executed?) but hooks may be able to help with this also.

See: Question: How can I end a Lua thread cleanly? for an example of using hooks.

Community
  • 1
  • 1
CiscoIPPhone
  • 9,457
  • 3
  • 38
  • 42
2

You can use:

os.execute("sleep 1") -- I think you can do every command of CMD using os.execute("command")

or you can use:

function wait(waitTime)
    timer = os.time()
    repeat until os.time() > timer + waitTime
end

wait(YourNumberHere)
grmmhp
  • 131
  • 3
1

You want  win.Sleep(milliseconds), methinks.

Yeah, you definitely don't want to do a busy-wait like you describe.

chaos
  • 122,029
  • 33
  • 303
  • 309
1

I started with Lua but, then I found that I wanted to see the results instead of just the good old command line flash. So i just added the following line to my file and hey presto, the standard:

please press any key to continue...

os.execute("PAUSE")

My example file is only a print and then a pause statment so I am sure you don't need that posted here.

I am not sure of the CPU implications of a running a process for a full script. However stopping the code mid flow in debugging could be useful.

Matt Johnson
  • 1,913
  • 16
  • 23
Ian
  • 11
  • 1
1

I believe for windows you may use: os.execute("ping 1.1.1.1 /n 1 /w <time in milliseconds> >nul as a simple timer. (remove the "<>" when inserting the time in milliseconds) (there is a space between the rest of the code and >nul)

Cruz Jean
  • 59
  • 1
  • 2
  • 7
1
cy = function()
    local T = os.time()
        coroutine.yield(coroutine.resume(coroutine.create(function()
    end)))
    return os.time()-T
end
sleep = function(time)
    if not time or time == 0 then 
        time = cy()
    end
    local t = 0
    repeat
        local T = os.time()
        coroutine.yield(coroutine.resume(coroutine.create(function() end)))
        t = t + (os.time()-T)
    until t >= time
end
Descaii
  • 11
  • 1
1

You can do this:

function Sleep(seconds)
    local endTime = os.time() + seconds
    while os.time() < endTime do
    end
end
print("This is printed first!")
Sleep(5)
print("This is printed 5 seconds later!")
1

You could try this:

function wait(seconds)
    local start = os.time()
    repeat until os.time() > start + seconds
end
wait(5) print("cargo. Cargo what? Cargo, storage.") -- waits 5 seconds and then prints

It worked for me in Lua CLI.

Kia
  • 9
  • 6
1

It's also easy to use Alien as a libc/msvcrt wrapper:

> luarocks install alien

Then from lua:

require 'alien'

if alien.platform == "windows" then
    -- untested!!
    libc = alien.load("msvcrt.dll")
else
    libc = alien.default
end 

usleep = libc.usleep
usleep:types('int', 'uint')

function sleep(ms)
    while ms > 1000 do
        usleep(1000)
        ms = ms - 1000
    end
    usleep(1000 * ms)
end

print('hello')
sleep(500)  -- sleep 500 ms
print('world')

Caveat lector: I haven't tried this on MSWindows; I don't even know if msvcrt has a usleep()

DSA
  • 11
  • 1
0

This should work:

    os.execute("PAUSE")
Anonymous
  • 9
  • 1