Author Topic: Sleep / Wait / Pause / Delay  (Read 8140 times)

0 Members and 1 Guest are viewing this topic.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Sleep / Wait / Pause / Delay
« on: October 02, 2014, 07:31:51 AM »
This was always something I didn't like too much in AutoLisp. Officially you have 2 options:
  • Use the delay command to pause execution
  • Loop until the specified time has crept by
The first one isn't always possible - e.g. you might not want a command run at this time, or it's running in DBX?

The second one is probably the most accurate ... but I don't like it too much as it simply hogs the Lisp thread completely - which in turn is thus hogging the ACad thread. So if you're waiting for something to complete in ACad (say executed through send-string / send-command asynchronously) - this sort of "wait-while-time-not-elapsed" loop means that other command never gets any access to the CPU and would probably never complete.

Alternatives would be to make some ARX/DotNet lisp function which then uses a "true" sleep call. I.e. use something like an event or a thread instead of simply testing the time at each cycle the CPU has. But that means you need to then install and load such ARX/DLL in order to use it - not to mention it needs updating depending on the version of ACad.

Anyhow, what about using something available "for all" (well at least for most on Windows) ... VBScript has a Sleep function which does this. So then how to have AutoLisp make use of it? Unfortunately the Sleep function is a statement in VBS - not a method of some object VLisp can link to. So no direct calling of this is possible ... but what about "indirectly"? E.g.

Code - Auto/Visual Lisp: [Select]
  1. (setq *Sleep:Error* 40)
  2.  
  3.  
  4. (defun Sleep  (milliSecs / fn f start vbs)
  5.   (setq start (getvar 'millisecs))
  6.   (if (and (setq fn (vl-filename-mktemp "Sleep.vbs")) (setq f (open fn "w")))
  7.     (progn (princ (strcat "WScript.Sleep " (itoa (- milliSecs *Sleep:Error*))) f)
  8.            (close f)
  9.            (setq vbs (vlax-get-or-create-object "WScript.Shell"))
  10.            (vlax-invoke-method vbs "Run" fn 0 :vlax-true)
  11.            (vlax-release-object vbs)
  12.            (setq *Sleep:Error* (+ *Sleep:Error* (- (getvar 'millisecs) start milliSecs))))))
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Sleep / Wait / Pause / Delay
« Reply #1 on: October 03, 2014, 04:30:35 AM »
The problem with this function is that the first time you call:
Code: [Select]
(setq vbs (vlax-get-or-create-object "WScript.Shell"))There will be a 'big' delay. I think this should be accounted for. But because of this delay the function is not reliable, especially for short sleep periods.

Code - Auto/Visual Lisp: [Select]
  1.  
  2. (setq *Sleep:Error* 40)
  3.  
  4. (defun Sleep (period / fileName filePointer timeCreate timeStart wshObject)
  5.   (setq timeStart (getvar 'millisecs))
  6.   (setq wshObject (vlax-get-or-create-object "WScript.Shell"))
  7.   (setq timeCreate (getvar 'millisecs))
  8.   (if (< period (- timeCreate timeStart))
  9.     (vlax-release-object wshObject)
  10.     (if
  11.       (and
  12.         (setq fileName (vl-filename-mktemp "Sleep.vbs"))
  13.         (setq filePointer (open fileName "w"))
  14.       )
  15.       (progn
  16.         (write-line (strcat "WScript.Sleep " (itoa (- period (- timeCreate timeStart) *Sleep:Error*))) filePointer)
  17.         (close filePointer)
  18.         (vlax-invoke-method wshObject "Run" fileName 0 :vlax-true)
  19.         (vlax-release-object wshObject)
  20.         (setq *Sleep:Error* (+ *Sleep:Error* (- (getvar 'millisecs) timeStart period)))
  21.       )
  22.       (vlax-release-object wshObject)
  23.     )
  24.   )
  25. )

Note: BricsCAD has a built-in Sleep function.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Sleep / Wait / Pause / Delay
« Reply #2 on: October 03, 2014, 05:25:21 AM »
There will be a 'big' delay. I think this should be accounted for. But because of this delay the function is not reliable, especially for short sleep periods.
Very true. I was thinking of including such into the initialization of that "error" compensation. On mine the write to file and execute takes between 30 to 50 msec (that's why it's initialized to 40). The first create object takes a bit longer than that though.

The other idea would be to initialize a global propagated variable with the com object on load. Also it might need lots more complication to accommodate very short times (e.g. < 100 ms) - e.g. reverting to the normal loop-until idea for such short times.

Tried this idea (including a warmup call):
Code - Auto/Visual Lisp: [Select]
  1. (setq *Sleep:Error* 40)
  2. (or *Sleep:VBS*
  3.     (setq *Sleep:VBS* (vlax-get-or-create-object "WScript.Shell"))
  4.     (vl-propagate '*Sleep:VBS*))
  5.  
  6. (defun Sleep  (mSec / fn f start stop)
  7.   (setq start (getvar 'millisecs)
  8.         stop  (+ start mSec))
  9.   (if (< mSec (* *Sleep:Error* 3))
  10.     (while (< (getvar 'millisecs) stop))
  11.     (progn
  12.       (if (and (setq fn (vl-filename-mktemp "Sleep.vbs")) (setq f (open fn "w")))
  13.         (progn (princ (strcat "WScript.Sleep " (itoa (- mSec *Sleep:Error*))) f)
  14.                (close f)
  15.                (vlax-invoke-method *Sleep:VBS* "Run" fn 0 :vlax-true)
  16.                (setq *Sleep:Error* (+ *Sleep:Error* (- (getvar 'millisecs) start mSec))))
  17.         (while (< (getvar 'millisecs) stop))))))
  18.  
  19. (Sleep (* *Sleep:Error* 4))
  20. (Sleep (* *Sleep:Error* 4))
  21.  
  22. (defun testSleep  (milliSecs / start stop)
  23.   (setq start (getvar 'millisecs))
  24.   (Sleep milliSecs)
  25.   (setq stop (getvar 'millisecs))
  26.   (princ "Expected ")
  27.   (princ milliSecs)
  28.   (princ "msec\tResult ")
  29.   (princ (- stop start))
  30.   (princ "msec")
  31.   (princ))

Seems to work (as expected Lisp's getvar millisecs is only accurate to within some 30ms so smaller values are not even testable):
Code: [Select]
; 7 forms loaded from #<editor "J:/Documents/AutoLisp Tests/Sleep.LSP">
_$ (testSleep 10)
Expected 10msec Result 16msec
_$ (testSleep 50)
Expected 50msec Result 63msec
_$ (testSleep 100)
Expected 100msec Result 109msec
_$ (testSleep 150)
Expected 150msec Result 156msec
_$ (testSleep 400)
Expected 400msec Result 374msec
_$ (testSleep 1000)
Expected 1000msec Result 1014msec
_$ (testSleep 1000)
Expected 1000msec Result 999msec
_$ (testSleep 1000)
Expected 1000msec Result 998msec
_$ (testSleep 200)
Expected 200msec Result 218msec
_$ (testSleep 300)
Expected 300msec Result 297msec

As for BC having the Sleep ... +1, I wish AC could get such things as standard instead of needing some extensions written in ARX/DotNet (which have their own issues).
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

VovKa

  • Water Moccasin
  • Posts: 1631
  • Ukraine
Re: Sleep / Wait / Pause / Delay
« Reply #3 on: October 03, 2014, 06:48:39 AM »
(vlax-invoke-method *Sleep:VBS* "Run" fn 0 :vlax-true) doesn't work for me
Quote
_1$ (vlax-dump-Object *Sleep:VBS* t)
; IWshShell3: Shell Object Interface
; Property values:
;   CurrentDirectory = ...Indexed contents not shown...
; Methods supported:
;   Exec (2)

VovKa

  • Water Moccasin
  • Posts: 1631
  • Ukraine
Re: Sleep / Wait / Pause / Delay
« Reply #4 on: October 03, 2014, 06:54:47 AM »
i have this
Code: [Select]
(defun vk_Sleep (Time / objHTTP)
  (if (setq objHTTP (vlax-create-object "WinHTTP.WinHTTPRequest.5.1"))
    (progn (vl-catch-all-apply
     (function (lambda ()
(vlax-invoke-method
   objHTTP
   "Open"
   "GET"
   "http://192.0.2.0"
   :vlax-false
)
(vlax-invoke-method objHTTP "SetTimeouts" 0 Time 0 0)
(vlax-invoke objHTTP "Send")
       )
     )
   )
   (vlax-release-object objHTTP)
   Time
    )
  )
)
« Last Edit: October 05, 2014, 05:07:58 PM by VovKa »

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Sleep / Wait / Pause / Delay
« Reply #5 on: October 03, 2014, 08:25:12 AM »
i have this
I suppose that's another way also. Was looking at that also. Also tried calling the ping command with a timeout set.

Though still with the same issue about initializing the com object. And not to mention you're waiting for an exception ... let me show what happens (because of this):
Code: [Select]
_$ (testSleep vk_Sleep 100)
Expected 100msec Result 21107msec
_$ (testSleep vk_Sleep 1000)
Expected 1000msec Result 21139msec
_$ (testSleep vk_Sleep 100000)
Expected 100000msec Result 20998msec
As if the time entered matters nothing - it will always wait around 21 sec. At least on my PC.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Sleep / Wait / Pause / Delay
« Reply #6 on: October 03, 2014, 08:34:03 AM »
(vlax-invoke-method *Sleep:VBS* "Run" fn 0 :vlax-true) doesn't work for me
Quote
_1$ (vlax-dump-Object *Sleep:VBS* t)
; IWshShell3: Shell Object Interface
; Property values:
;   CurrentDirectory = ...Indexed contents not shown...
; Methods supported:
;   Exec (2)
Strange. On mine it works even though I've got the same dump-object:
Code: [Select]
_$ (vlax-dump-Object *Sleep:VBS* t)
; IWshShell3: Shell Object Interface
; Property values:
;   CurrentDirectory = ...Indexed contents not shown...
; Methods supported:
;   Exec (2)
T

And yet the WshShell object works fine with those hidden stuff.
Code: [Select]
_$ (vlax-get-property *Sleep:VBS* "SpecialFolders")
#<VLA-OBJECT IWshCollection 0000000034f84760>
_$ (vlax-invoke-method *Sleep:VBS* "ExpandEnvironmentStrings" "%WinDir%")
"C:\\Windows"
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Sleep / Wait / Pause / Delay
« Reply #7 on: October 03, 2014, 11:05:26 AM »
FWIW: Creating a temp .vbs script is not necessary if you supply a command line parameter.
Sleep.vbs:
Code: [Select]
WScript.Sleep WScript.Arguments(0)Lisp:
Code: [Select]
(vlax-invoke-method wshObject "Run" (strcat (findfile "Sleep.vbs") " " (itoa period)) 0 :vlax-true)

VovKa

  • Water Moccasin
  • Posts: 1631
  • Ukraine
Re: Sleep / Wait / Pause / Delay
« Reply #8 on: October 03, 2014, 06:04:01 PM »
Quote
let me show what happens (because of this):
Try to change the url
The url must be 'unpingable'

as of http://en.wikipedia.org/wiki/Reserved_IP_addresses
i think 192.0.2.0 can be used
Code: [Select]
_$ (testSleep 100)
Expected 100msec Result 109msec
_$ (testSleep 300)
Expected 300msec Result 312msec
_$ (testSleep 500)
Expected 500msec Result 500msec
_$ (testSleep 1000)
Expected 1000msec Result 1000msec
_$ (testSleep 5000)
Expected 5000msec Result 5000msec
_$ (testSleep 10000)
Expected 10000msec Result 10000msec
« Last Edit: October 05, 2014, 05:07:24 PM by VovKa »

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Sleep / Wait / Pause / Delay
« Reply #9 on: October 06, 2014, 07:16:38 AM »
FWIW: Creating a temp .vbs script is not necessary if you supply a command line parameter.
Good point ... would need to adjust so that file is findable on the search path (or perhaps create it if not).

Try to change the url
Strange, must be something to do with our network here. No matter what IP I use it seems to take 21 seconds for all of them.

Code: [Select]
_$ (testSleep vk_Sleep 100)
Expected 100msec Result 21091msec
_$ (testSleep Sleep 100)
Expected 100msec Result 109msec
_$ (testSleep Sleep 1000)
Expected 1000msec Result 983msec
_$ (testSleep vk_Sleep 1000)
Expected 1000msec Result 21107msec
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.