B4J Tutorial [B4X] Resumable Subs - Sleep / Wait For

Discussion in 'B4J Tutorials' started by Erel, Apr 19, 2017.

Thread Status:
Not open for further replies.
  1. Gary Miyakawa

    Gary Miyakawa Active Member Licensed User

    This is my testing code and it definitely doesn't "sleep" for 30 seconds.

    Code:
    'Non-UI application (console / server application)
    #Region Project Attributes
        
    #CommandLineArgs:
        
    #MergeLibraries: True
    #End Region

    Sub Process_Globals
      
    End Sub

    Sub AppStart (Args() As String)

        
    Log(DateTime.Now)
        hold(
    30000)
        
    Log(DateTime.now)
        StartMessageLoop
    End Sub

    Sub hold(time As Int)
      
        Sleep (time)
      
    End Sub
    Thoughts ? BTW, I'm running this in a RPI...
     
    Last edited: Apr 23, 2017
    Jones Hone likes this.
  2. Enrique Gonzalez R

    Enrique Gonzalez R Well-Known Member Licensed User

    It is async.
    That means that between the 2 datetime.now will not be any delay.

    Try writing the second daytime.now inside the hold function

    Edit: and after the sleep
     
  3. Erel

    Erel Administrator Staff Member Licensed User

    That's 100% correct.

    Quoting the tutorial:
    Whenever Sleep or Wait For are called, the current sub is paused. This is equivalent to calling Return.

    Only the resumable sub itself is paused and resumed.
    Correct code:
    Code:
    Sub AppStart (Args() As String)
        hold(
    30000)
        StartMessageLoop
    End Sub

    Sub hold(time As Int)
        
    Log(DateTime.Now)
        Sleep (time)
       
    Log(DateTime.now)
    End Sub
     
  4. Erel

    Erel Administrator Staff Member Licensed User

    Tip: As explained in the first post, when one sub calls a second resumable sub, the code in the first sub will continue after the first Sleep or Wait For call (in the second sub).

    If you want to wait for the second sub to complete then you can raise an event from the second sub and wait for it in the first:
    Code:
    Sub FirstSub
       
    Log("FirstSub started")
       SecondSub
       
    Wait For SecondSub_Complete
       
    Log("FirstSub completed")
    End Sub

    Sub SecondSub
       
    Log("SecondSub started")
       Sleep(
    1000)
       
    Log("SecondSub completed")
       CallSubDelayed(Me, 
    "SecondSub_Complete")
    End Sub
    Logs:
    FirstSub started
    SecondSub started
    SecondSub completed
    FirstSub completed

    Notes:
    - It is safer to use CallSubDelayed than CallSub. CallSub will fail if the second sub is never paused (for example if the sleep is only called based on some condition).
    - There is an assumption here that FirstSub will not be called again until it is completed.
    - In B4J v5.50 beta #2 there will be a warning about a missing sub. This is fixed for the next update.
     
  5. Kirby Leeper

    Kirby Leeper Member Licensed User

    Just fansastic work. I'm glad I found B4X.
     
    Gary Miyakawa likes this.
  6. rwblinn

    rwblinn Well-Known Member Licensed User

    Thanks for this great feature.
    Build a small test app with a Progressbar Class which is called by the Main Class via timer.
    As this is a new feature, pls share if there are other / better ways to show an updating progressbar in a class.

    EDIT: Removed Wait For and added Sleep (based on guidance Post #28).

    Main Class Snippet
    Code:
    Sub Process_Globals
        
    Public tmr As Timer
        
    Public tmrinterval As Long = 500
        
    Private ProgressValue As Int = 0
        
    Private ProgressDlg As ProgressDialog
    End Sub

    Sub AppStart (Form1 As Form, Args() As String)
        ProgressDlg.Initialize(
    True)
        tmr.Initialize(
    "tmr", tmrinterval)
        tmr.Enabled = 
    False
    End Sub

    Sub tmr_Tick
        ProgressValue = ProgressValue + 
    10
        ProgressDlg.ProgressUpdate(ProgressValue)
        Sleep(
    0)
        
    If ProgressValue = 100 Then tmr.Enabled = False
    End Sub
    ProgressBar Class Snippet
    Code:
    Sub Class_Globals
        
    Private fx As JFX
        
    Private frm As Form
        
    Private ProgressBar1 As ProgressBar
        
    Private btnClose As Button
        
    Private mCloseAtCompletion As Boolean = False
    End Sub

    Public Sub Initialize(CloseAtCompletion As Boolean)
        frm.Initialize(
    "frm"200100)
        frm.SetFormStyle(
    "UNDECORATED")
        frm.Resizable = 
    False
        frm.RootPane.LoadLayout(
    "ProgressDialog")
        ProgressBar1.Progress = 
    0
        mCloseAtCompletion = CloseAtCompletion
        btnClose.Visible = 
    Not(mCloseAtCompletion)
    End Sub

    'Update the progress bar with a value between 0 and 100
    public Sub ProgressUpdate(value As Double)
        frm.show
        ProgressBar1.Progress = 
    Round(value) / 100
        
    If mCloseAtCompletion And ProgressBar1.Progress = 1 Then frm.close
    End Sub

    Sub btnClose_Action
        frm.close
    End Sub
    upload_2017-4-25_17-13-1.png
     

    Attached Files:

    Last edited: Apr 25, 2017
  7. Erel

    Erel Administrator Staff Member Licensed User

    I don't think that you are using Wait For correctly. It is not needed in the code you posted.

    Example of using Sleep to update the progress bar inside a long loop:
    Code:
    Sub SubThatDoesAVeryLongCalculation
       
    Dim mx As Long = 100000000
       
    Dim i As Long
       
    For i = 1 To mx
         
    If i Mod 10000 = 0 Then
           ProgressDlg.ProgressUpdate(i * 
    100 / mx)
           Sleep(
    0)
         
    End If
       
    Next
    End Sub
    Note that I made a few changes to your project. See the attachment.
     

    Attached Files:

    pesquera and rwblinn like this.
  8. rwblinn

    rwblinn Well-Known Member Licensed User

    Thanks for clarity = gives a better understanding when to use Wait For and Sleep.
    For the test app I made, by keeping on using a timer, have removed the Wait For (in AppStart) and added Sleep(0) to the tmr_Tick after Progress Update, which works fine.
     
  9. swissmade

    swissmade Active Member Licensed User

    Can not wait to get the Release.
    Thanks Erel
     
  10. Enrique Gonzalez R

    Enrique Gonzalez R Well-Known Member Licensed User

    Hello!

    This work:

    Code:
    CallSubDelayed(Main, "initSQL_Complete")

        
    wait for initSQL_Complete 'in Main
    But triggers an IDE warning for Sub initSQL_Complete not found!
     
    Last edited: May 4, 2017
  11. Erel

    Erel Administrator Staff Member Licensed User

    This is fixed for the next update.
     
    Enrique Gonzalez R likes this.
  12. Enrique Gonzalez R

    Enrique Gonzalez R Well-Known Member Licensed User

    I have a question regarding duck typing.

    i am working on a small example where i am lazy enough to write a code several times:

    Code:
    'Panels, tableviews, radioButtons.
        Dim n() As Node = Array As Node (Pane1,twPerfiles,twEmpleos,rdbSubTabla0,rdbSubTabla1)
       
        
    For Each n2 As Node In n
            n2.Alpha = 
    0
            n2.visible = 
    True
            n2.SetAlphaAnimated(
    750,1)
           
            
    wait for (n2) pane1_AnimationCompleted
           
        
    Next
    It will run for pane1 only, after that it will just wait eternally for twPerfiles, because the name of the event is not the same.
    will it be possible to run this event with duck Typing?
     
  13. Erel

    Erel Administrator Staff Member Licensed User

    Note that the program will not actively wait for the event. It is similar to having a sub that is never called.

    You will need to set the EventName parameter of all the nodes to be the same.

    Or use Sleep(750) instead of waiting for the event.
     
    Enrique Gonzalez R likes this.
  14. PSEAD

    PSEAD Member Licensed User

    Is B4A getting resumable subs too?
     
  15. Erel

    Erel Administrator Staff Member Licensed User

    Yes.
     
    PSEAD likes this.
  16. jahswani

    jahswani Active Member Licensed User

    Thanks the next step will ne to make these subs return values.;).
     
  17. Erel

    Erel Administrator Staff Member Licensed User

    This can never be supported as the code execution returns when Sleep or Wait For are called. The sub is later resumed. Long after the calling sub has already completed.
     
  18. jahswani

    jahswani Active Member Licensed User

    :rolleyes::rolleyes::rolleyes::rolleyes::rolleyes: I understand now.
     
  19. leitor79

    leitor79 Active Member Licensed User

    Great Feature, thank you very much!

    I have a question; I don't get why the output of the code quoted here is different than the output in this gif:

    [​IMG]


    Regards,

     
  20. Enrique Gonzalez R

    Enrique Gonzalez R Well-Known Member Licensed User

    because of the wait for here

    Code:
    Wait For SecondSub_Complete
    without this line, sub1 will continue even when sub2 has not finished.

    this line is telling the code, wait until sub2 is finished to continue with sub1.
     
    Erel likes this.
Thread Status:
Not open for further replies.
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice