Waiting For Multiple Threads To Complete

From my own Xojo API service, I would like to call several other services concurrently, and then return a JSON response containing data from all of these services.

In C#, there are several ways to do this, one of which is in this sample code:

private async Task GetPWGsrvAsync()
{
    var widgetService = new WidgetService();
    var prodService = new ProductService();
    var gizmoService = new GizmoService();
    
    var widgetTask = widgetService.GetWidgetsAsync();
    var prodTask = prodService.GetProductsAsync();
    var gizmoTask = gizmoService.GetGizmosAsync();

    await Task.WhenAll(widgetTask, prodTask, gizmoTask);
     
    var pwgVM = new ProdGizWidgetVM(
       widgetTask.Result,
       prodTask.Result,
       gizmoTask.Result
       );

How do I express similar functionality in Xojo? I’m wondering what the best practice is for waiting for multiple threads to finish and then returning a response. Do I have each thread set a property that I check for, and do I sleep the current thread in a loop while waiting?

Thanks for any ideas. I wasn’t sure what the best practice was for doing this in Xojo. In my searches on the forum, I couldn’t find an exact answer to how Xojo should be used to have the same effect as the C# sample code above, so I apologize if this has been asked before (I can’t imagine it hasn’t - but I couldn’t find a good explanation).

Concurrency is one of Xojo’s weaknesses compared to more modern languages. It’s really starting to show its age not supporting things like promises.

So you’ll need some manually work to hook this up. Something having each set a property at end like ACompeted, BCompleted, CCompleted. Have them each the fire a method that immediately checks all three properties and returns early if any are false. This way the last to complete will run the next part of the code. If you need to manipulate the UI, you’ll need to use the user interface update event instead, but the concept is generally the same.

It’s not exactly elegant, but… like I said, it’s an old language. I think the last time we got a new language feature was… enums. Handlers? If()? I can’t remember exactly, but it’s been a while.

2 Likes

While waiting for ACompleted, BCompleted and CCompleted to be true, should I do this in a loop while calling Thread.SleepCurrent?

I’m not sure if I am missing something when you say that each should fire a method that checks all three properties and returns early if any are false.

Thanks for the tips.

When your thread ends, it fires its Completed event. In that event, for each thread, you execute a piece of code in the enclosing app that checks to see if all threads have completed, and then returns if that is the case.

1 Like

If I am in a HandleURL event, instead of a normal application, wouldn’t I need to sleep until all three are completed and then send the response?

Oh that complicates life…

I don’t think there’s any point to use threads in this case, since the request should already be threaded. Just call them synchronously in sequence. Your code will be simpler, and you won’t really lose much.

1 Like

I was hoping that would not be the answer, but I will go with that lol!

Thank you.

BTW - What is the negative to concurrently calling three services and gathering results at the same time, while waiting for all three to complete in a loop that calls Thread.SleepCurrent for short milliseconds?

If each took 5 seconds to complete, wouldn’t it save almost 10 seconds on the calls?

Yes, it could. But getting it to do what you want is going to be a challenge. Yes, your best bet - if you really want to take this approach - is to sleep the HandleURL thread and wait for the other threads to complete.

In this case, fire off your three threads, and just as before they set a property to true when done. Then in your HandleURL do something like

While (AComplete And BComplete And CComplete) = False
  Thread.Current.Sleep(50)
Wend

Then continue with your code. The part that’s going to make this annoying is getting data into and out of those three threads. Also, what if there is an exception in ThreadB? BComplete will never become true, so now you have an infinite loop. So you’ll need to track the amount of time waiting, and decide what to do if you have partial success.

Using synchronous URLConnection requests will allow you to write more direct code at the cost of letting them run at the same time.

1 Like

Thank Thom for such great info and advice. I really appreciate it

My app Mail Archiver can download external content for emails. Downloading one email at a time was too slow. Therefore, I made a queue with a list of sockets. That worked fine. I had a list of urls to download and an array of 5 sockets. When a download was finished the next item on the queue was downloaded. The socket at that time crashed now and then. Using CURLSMultiMBS is much easier and less crashy.

1 Like