Android Question Order of completion of multiple async calls

ddk1

Member
Licensed User
If I make repeated async calls to a sub, each time waiting for the completeion, can I be sure the order of completion is the same as the calls made.
eg:
for i = 0 to 5
    strFile = strArray(i)
    sf = ftp.DownloadFile(strFile, True, File.DirInternal, strFile)
    Wait For (sf) ftp_DownloadCompleted (ServerPath As String, Success As Boolean)
    If Success Then
        ' can I gurantee strFile here is same as was set 4 lines above

In this example, can I trust that upon completion, strFile is the same as it was when the call was made to ftp.Download, or do I need to interrogate ServerPath to reassign what strFile is upon completion.
I understand if I did not use Wait For and relied on Sub ftp_DownloadCompleted() then it certainly could arrive at Sub ftp_DownloadCompleted() out of order.
 

ddk1

Member
Licensed User
Put another way:
B4X:
    strFile = "file1"
    sf = ftp.DownloadFile(strFile, True, File.DirInternal, strFile)
    Wait For (sf) ftp_DownloadCompleted (ServerPath As String, Success As Boolean)
   
    strFile = "file2"
    sf = ftp.DownloadFile(strFile, True, File.DirInternal, strFile)
    Wait For (sf) ftp_DownloadCompleted (ServerPath As String, Success As Boolean)

Will file2 even start downloading before file1 is finished, given the Wait For (sf) ftp_DownloadCompleted
 
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
Line 5 onward of your code will not take place until lines 1 to 3 are completed. That's the meaning of Wait For.
If you make the download a sub then you can start the downloading at the same time.

B4X:
Private Sub CallingSub
    downloadedFiles = 0     'Global Int
    downloadFile("File1")
    downloadFile("File2")
    Do While downloadedFiles < 2
        Sleep(200)
    Loop
    'Both loaded (not necessarily successfully - you have to track that separately - two more globals)
End Sub

Private Sub downloadFile(strFile As String)
    sf = ftp.DownloadFile(strFile, True, File.DirInternal, strFile)
    Wait For (sf) ftp_DownloadCompleted (ServerPath As String, Success As Boolean)
    downloadedFiles = downloadedFiles + 1
End Sub
 
Last edited:
Upvote 0

ddk1

Member
Licensed User
Thanks. It occurred to me I could test it easily enough, which I did, and it confirms what you said. I was concerned that maybe the sub could timeout (there is a setting eg. ftp.TimeoutMs = 5000) and thus complete out of order but it seems not. Many thanks.
 
Upvote 0

emexes

Expert
Licensed User
'Both loaded (not necessarily successfully - you have to track that separately - two more globals)

Lol that struck a nerve... re: situations like that where it'd be useful if the ResumableSub object had a ReturnValue property in addition to the Completed property.

On a related note, I'm mildly uncertain about using
B4X:
If ResSub.Completed = False Then
    Wait For (ResSeb) Complete
End If
because it feels like it's possible that ResSub might complete after the If Then but before the Wait For.

Global Variables to the rescue again!
 
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
if the ResumableSub object had a ReturnValue

Resumable Subs can have return values (see the Success return from download).
But if you want to start loading two or more files asynchronously, that return value needs to be recorded.

Here is a method that doesn't use a global.

B4X:
Private Sub CallingSub
    Dim Results As Map = CreateMap()
    downloadFile("File1", Results)
    downloadFile("File2", Results)
    Do While "" = Results.GetDefault("File1", "") Or "" = Results.GetDefault("File2", "")
        Sleep(200)
    Loop
    Log("File1 loaded and " & Results.Get("File1"))
    Log("File2 loaded and " & Results.Get("File2"))
End Sub

Private Sub downloadFile(strFile As String, Results As Map)
    sf = ftp.DownloadFile(strFile, True, File.DirInternal, strFile)
    Wait For (sf) ftp_DownloadCompleted (ServerPath As String, Success As Boolean)
    Results.Put(strFile, IIf(Success, "success", "failed"))
End Sub
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
because it feels like it's possible that ResSub might complete after the If Then but before the Wait For.
No, since there will be no interruption of processing until the Wait For is executed. Nothing on the event queue will be processed until the code relinquishes control. If you use threading outside of B4A, you may have to worry about other problems, such as multiple read/write access to the same object/memory location, trying to access UI elements of the main thread, etc.
 
Upvote 0

emexes

Expert
Licensed User
Nothing on the event queue will be processed until the code relinquishes control.

Ok, that's useful to know. šŸ™

Although, just to clarify: does that mean that if a Java/Android program doesn't use any multi-thread facility, then code like "N = N - 1 : P = P + 1" is guaranteed to complete correctly, without risk of other code changing N or P at the same time?
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
without risk of other code changing N or P at the same time?
Ok, no expert here, but without threads / external forces (such as a debugger?) I don't see any risks of variables just changing willy-nilly (and I may be showing my language design ignorance here). Also, in the case above, if ResSub is a B4X resumable sub written in B4X, it's executed on the same thread as the calling sub, so it can't set the completed flag without having been given time to do so. ResSub will never (*) run simultaneously as any other code of your B4X app unless you invoke some threading shinanigans and then all bets are off.

(*) As of current (as I'm posting this) B4X language design
 
Upvote 0
Top