Threads, progressbars and Windows

I’m always having problems while updating progressbars or any other GUI element in Windows.

I have tried with the Task sample and with Timers, Timers seems to work a little better but not consistent. Of course the samples included with Xojo work fine also in Windows but once I add some intensive processing (not only ticks or sleep) or OLEObjects they don’t update the GUI.

Same code in Mac works perfectly but in Windows the whole window goes weird: controls are erased and repainted, not responding titles, etc.

My best solution has been using a canvas and a timer to update it via paint, seems to work better than native progressbar but still not well.

I know that Mac is the most used with Xojo, but I’m really curious if anyone is updating GUI’s in Windows during intensive threads.

Unfortunately, I’m in the same club, Alejandro. If I use non-threaded code on Windows, I can get reasonable updates of the UI elements. However, nothing that I’ve tried using the UI Task or normal Thread / Timers is even close to reasonable under Windows (Linux splits the difference).

I’m building a simple project to share with the Xojo team so that they can both see the lack of responsiveness and hopefully sort it out.

If you have anything that can be shared with them, please open a ticket on this (even if you need to mark it as private).

Thanks, Tim, I’m not alone :slight_smile:

With non-threaded code I get better responsiveness too but sometimes I’m forced to include DoEvents to make it really work. Using .NET I had to include DoEvents also and therefore I don’t expect a smooth refresh with Xojo but it’s really poor.

I have tried even with an Indeterminate ProgressBar which should just play the animation but it doesn’t works.

Lowering thread priority to 1 helps.

Will try to open a ticket.

From Craig and Kato’s liking of our posts, it looks like we’re definitely not alone :).

No. Never alone…

Agreed - App.DoEvents() seems to be my only working solution on Windows, as well. I’m making three examples for my feedback report - non-threaded but requiring DoEvents, Thread / Timer, UI Task.

I’ll post the report ID when it’s done.

Just as curiosity:, while debugging I have noticed that enabling Project - Profile code makes it run almost perfect, the whole interface is responsive and the progressbar updates smoothly.

Hmm, one option that I’ve never tried…

Is this for the thread/timer model, or the on-threaded version?

I have tried with thread, timer and own canvas based progressbar. If running build with code profile it is not as smooth as in the IDE but better than without profiling.

Tim, I was going to use the same “club” metaphor. =) But this isn’t a club, it’s a fact. For a long time.

I’m sure some of it is Windows itself though. But I feel REAL/Xojo uses that as an excuse mostly. I use DoEvents in these cases. There, I said it. If anyone wants to persecute me, show me a a fool-proof method that actually works, and actually TRY IT because you post it (that is, stay out of TheoryLand).

I just created a quick layout that had 5 labels to hole the contents of 5 fields returned in a shell’d process. I read the stdout from the shell (mode = 2) in a thread. In the thread, I used Me.Sleep(10) at the loop boundaries for looping through the lines returned. The UI doesn’t update until the task is finished using:

thMonitorShell.Run Do Dim myTicks As Integer = Ticks While Ticks < myTicks + 20 // should update ~3x per sec Wend Loop Until Not theShell.IsRunning

The thread updates variables that are then drawn in the UI via a Timer.

However, if I simply replace the ticks while loop with a call to App.DoEvents(10) in the Do Loop:

thMonitorShell.Run Do App.DoEvents(10) Loop Until Not theShell.IsRunning
The UI updates properly.

My quandary is that I can’t put the blame solely on the UI update performance as I’m also seeing serious performance penalties using the Shell under Windows and the String overhead involved with processing each line of text returned by the shell. For example, simply changing that last code to:

thMonitorShell.Run Do theShell.Poll App.DoEvents(10) Loop Until Not theShell.IsRunning
provides approximately a 10% improvement in speed in the number of lines that are handled in a loop. Additionally, I’ve seen instances under Windows where the Shell appears to continue running after the task is finished (IsRunning never turns False). Adding the Shell.Poll fixes that, as well. It doesn’t matter if Canonical is set or not.

One recommendation was to eliminate the wait loops and run the steps of my tasks via timers. That sort of works in that the UI updates, but the performance using the native Main runloop updates is still poor when compared to using the wait loop with App.DoEvents().

I’m really hoping that the code that I attach to the feedback report will help them sort this. I’m running on a 12 core, Intel Xeon running at 3.2GHz and there’s really no acceptable excuse for the performance hits I’m witnessing. I created the same project layout in Java, and the shell’s output actually returns empty reads in a large percentage of the loops when the Xojo code always has something in the Shell’s buffer. This basically translates to Java reading and processing the same external process’ output at almost 30x the performance of the Xojo code’s handling that same output.

(to hold the contents…)
Can’t edit again :expressionless:

I just created a small test project with one thread containing a while/wend loop and inside both a math operation and a call to the timer at every tick. In the timer, all it does is to update Value with a window property that the thread sets.

A while/wend loop is extremely voracious and in the main thread, it freezes the UI.

With the default thread priority of 5, the progressbar is quite erratic, if it ever starts.

With a thread priority of 1, everything runs smoothly.

Michel, that’s what the UIThreadingWithTask example project does.

Now, instead of a simple math function and a ProgressBar, try reading 20’s of lines of backend process output per second from a shell, split each line into component fields (separated by “|”), update the variables that represent each field, and then update the UI in the timer.

In Xojo, I have to throw away all but the last 2 lines of each Shell.ReadAll call to even come close to keeping up (using App.DoEvents).

So your problem is really with Shell and not with Thread. Have you tried putting your processing code in the DataAvailable event of the Shell and using a short-period Timer to poll the shell?

If you are using a synchronous shell, look no further. It ties everything until finished. An asynchronous shell will probably solve the issue.

If I do it this way, I don’t need the timer as the loop through the DataAvailable event is enough time. It’s only when using a thread that the clogged pipe occurs.

Not the problem - Shell.Mode = 2 and Shell.Timeout = -1 (also tried Shell.Canonical = True).

Threads are nothing but a distraction of execution from the main thread anyway. So they do consume resources which may already be overextended. Actually, as you have stated, threads tend to make matter worse in certain cases.

Could you not consider a helper app that communicates with the main app through IPC ? That should solve all resources issues.

Here’s something that might help my situation - does anyone have an example of reading and writing named pipes (FIFOs)? It might be less overhead to redirect stdin / stdout / stderr to named pipes and then read and write them using binary streams thus bypassing the shell for anything but executing the backend tool.

Also, can such a thing be done under Windows (I’ve never had a reason to try there)?