Thread Tools Display Modes
09/07/14, 02:51 AM   #1
Klingo
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 16
Wait for a function to end before continue

Hi

I have a function that is triggered by an event and within this function there are several sub-functions that are called.
The first sub-functions makes use of some "zo_callLater" and the end of this sub-function is reached earlier than all the "zo_callLater" are ended (they might take 2-3 seconds). So the second sub-function is already called although not all "zo_callLater" from the first sub-function have ended, which causes some problems in the addon.

Currently I deal with this situation in the following way:
The first sub-function returns "true" as soon as all "zo_callLater" calls are completed. I then check this value in a loop if it is "true" and only in that case allow the main function to call the second sub-function.
Lua Code:
  1. local mainFunction()
  2.     -- call the first sub-function that contains some 'zo_callLater'
  3.     local isCompleted = callFirstSubFunction()
  4.  
  5.     while (isCompleted == nil) do
  6.         -- do nothing; wait
  7.     end
  8.  
  9.     -- call the second sub-function
  10.     callAnotherSubFunction()
  11. end

It basically works, but I am not sure how bad (performance-wise) this solution is.
I don't see any game-freezing effects like a regular endless-loop would cause, but I thought there might be a better solution for this?

Klingo
  Reply With Quote
09/07/14, 05:10 AM   #2
Wykkyd
Are you Wykkyd Gaming?
 
Wykkyd's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 107
This is when I typically use the update tic. Update tic callbacks are "asynchronous". Your wait loop is "synchronous". It technically causes more churn, and locks the process until that loop ends.

Code:
local firstRunCalled = false
local firstRunComplete = false
local callFirst = function(...)
    -- do whatever has to happen first
    firstRunComplete = true
end
local callSecond = function()
    -- do your second thing here
end
local mainFunction = function(eventType,...)
    if firstRunCalled and eventType ~= nil then return end 
        -- eventType having a value means it came from the event handler, not our update tic. 
        -- Since we're already running, skip it until last pass completes
    if not firstRunCalled and eventType == nil then return end
        -- standard update tic but we're not processing
        -- so kick us out
    if not firstRunCalled then
        firstRunCalled = true
        firstRunComplete = false
        callFirst( ... )
    end
    if not firstRunComplete then return end
        -- kick us out if it isn't complete yet
    firstRunCalled = false
    callSecond()
end
EVENT_MANAGER:RegisterForUpdate("myaddon_mainfunction_updatetic", 100, mainFunction)
EVENT_MANAGER:RegisterForEvent( "myaddon_mainfunction_eventwatch", EVENT_WHATEVER, mainFunction)
Something like that, perhaps. Sorry, this is off the top of my head. Basically hook your mainFunction into both the event, and the update callback.

Last edited by Wykkyd : 09/07/14 at 05:13 AM.
  Reply With Quote
09/07/14, 06:28 AM   #3
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
Klingo, the snippet you posted looks ripped out of context, and unlike what you described. isCompleted is assigned exactly once, never changes value, so that loop is either done immediately, or runs forever

I'd slightly modify Wykkyd's method. In your event handler, check if an update func is registered - if yes, return immediately (or note that the whole process needs restarting; depends on what your addon does with the event), otherwise do required preparations and register for update. In update you can check elapsed time, call other functions when they're due, and after the last one is finished, unregister (or restart if there was another event).
  Reply With Quote
09/07/14, 01:33 PM   #4
Sasky
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 231
Originally Posted by Klingo View Post
Hi

I have a function that is triggered by an event and within this function there are several sub-functions that are called.
The first sub-functions makes use of some "zo_callLater" and the end of this sub-function is reached earlier than all the "zo_callLater" are ended (they might take 2-3 seconds). So the second sub-function is already called although not all "zo_callLater" from the first sub-function have ended, which causes some problems in the addon.

Currently I deal with this situation in the following way:
The first sub-function returns "true" as soon as all "zo_callLater" calls are completed. I then check this value in a loop if it is "true" and only in that case allow the main function to call the second sub-function.
Lua Code:
  1. local mainFunction()
  2.     -- call the first sub-function that contains some 'zo_callLater'
  3.     local isCompleted = callFirstSubFunction()
  4.  
  5.     while (isCompleted == nil) do
  6.         -- do nothing; wait
  7.     end
  8.  
  9.     -- call the second sub-function
  10.     callAnotherSubFunction()
  11. end

It basically works, but I am not sure how bad (performance-wise) this solution is.
I don't see any game-freezing effects like a regular endless-loop would cause, but I thought there might be a better solution for this?

Klingo
That's called busy waiting and is probably the worst-performance for waiting on something. You eat resources checking constantly, even though you don't need to.

The solution Wykkyd provided basically tones down how often you check.

If you have access to all functions you could also do something like this, where the check is at the end of each sub-call. This would keep the times you check for updates to a minimum.

Lua Code:
  1. local foo_done = false
  2. local bar_done = false
  3.  
  4. function checkEnd()
  5.     if foo_done and bar_done then
  6.         --call end stuff
  7.     end
  8. end
  9.  
  10. function foo()
  11.     --Do stuff
  12.     foo_done = true
  13.     checkEnd()
  14. end
  15.  
  16. function bar()
  17.     --Do other stuff
  18.     bar_done = true
  19.     checkEnd()
  20. end
  21.  
  22. function mainFunction()
  23.     foo_done = false
  24.     bar_done = false
  25.     --asynchronous calls
  26.     zo_callLater(foo, 100)
  27.     zo_callLater(bar, 100)
  28. end
  Reply With Quote
09/07/14, 03:08 PM   #5
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 648
There are two even better ways to accomplish this that do not use any sort of a timer to poll to see if it's ready.

#1 - Have the script you assign to the zo_callLater call actually call the next function when it's finished.
Lua Code:
  1. local function callAnotherSubFunction()
  2.      --do other stuff after zo_callLater is finished
  3. end
  4.  
  5. local function callFirstSubFunction()
  6.      --do stuff
  7.      zo_callLater(100, function()
  8.                --do something later
  9.                callAnotherSubFunction()
  10.           end)
  11. end
  12.  
  13. local function mainFunction()
  14.     callFirstSubFunction()
  15. end


#2 - Use callbacks. Register for a custom callback (a custom event) which is fired by the zo_callLater call, and have your callback handler be the second function.
Lua Code:
  1. local function callFirstSubFunction()
  2.      --do stuff
  3.      zo_callLater(100, function()
  4.                --do something later
  5.                CALLBACK_MANAGER:FireCallback("zo_callLaterFinished")
  6.           end)
  7. end
  8.  
  9. local function callAnotherSubFunction()
  10.      --do other stuff after zo_callLater is finished
  11. end
  12.  
  13. local function mainFunction()
  14.     callFirstSubFunction()
  15. end
  16.  
  17. CALLBACK_MANAGER:RegisterCallback("zo_callLaterFinished", callAnotherSubFunction)
  Reply With Quote
09/11/14, 02:36 PM   #6
Fyrakin
 
Fyrakin's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 129
Originally Posted by Seerah View Post
There are two even better ways to accomplish this that do not use any sort of a timer to poll to see if it's ready.
I'd go with callbacks for this. Its more efficient.
  Reply With Quote
09/12/14, 12:38 PM   #7
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 648
Originally Posted by Fyrakin View Post
I'd go with callbacks for this. Its more efficient.
Oops - yes. I forgot to put that this would be my preference.
  Reply With Quote
09/14/14, 07:19 AM   #8
Klingo
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 16
Thanks a lot for all the feedback, it's much appreciated!
The solution with callbacks definitely seems to be the best way to go on with.
  Reply With Quote

ESOUI » Developer Discussions » Lua/XML Help » Wait for a function to end before continue

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off