Thread acting as a timer issue

Hi folks.

I have run into an issue that is making me frustrated.

I’m running Xojo 2025R2 on mac Sonoma.

I have a thread that will update on a window a label, so people can see the program is running, even if it isn’t showing anything.

here is the code for threadForRunningTime.Run

static runTimerValue As Integer

While app.runningTime = TRUE

runTimerValue = runTimerValue + 1

Me.AddUserInterfaceUpdate("timeCounter":runTimerValue)

Thread.SleepCurrent(1000)

Wend

And in my threadForRunningTime.UserInterfaceUpdate:

Var seconds As Integer

If data.LastIndex >= 0 Then

Var arg As Dictionary = data(data.LastIndex)

If arg.HasKey("timeCounter") Then
seconds = arg.Value("timeCounter").IntegerValue
labelProgramRunTime.Text = seconds.ToString
End If

End If

The issue I have is that instead of getting 1..2..3.. it screams up to tens of thousands. And just stops.

Or locks up my program and xojo.

If I remove the Me.AddUserInterface… it seems to act normally according to my log file.

7:12:19 PM : There are 45 total rows
7:12:21 PM : ******** MATCH FOUND ********
: I = 4 J = 6
: ******** MATCH FOUND ********
: I = 4 J = 18
: ******** MATCH FOUND ********
: I = 4 J = 20
7:12:22 PM : ******** MATCH FOUND ********
: I = 6 J = 18
: ******** MATCH FOUND ********
: I = 6 J = 20
7:12:23 PM : ******** MATCH FOUND ********
: I = 9 J = 16
: ******** MATCH FOUND ********
: I = 9 J = 19
: ******** MATCH FOUND ********
: I = 9 J = 23
7:12:24 PM : ******** MATCH FOUND ********
: I = 11 J = 12
7:12:25 PM : ******** MATCH FOUND ********
: I = 13 J = 37
: ******** MATCH FOUND ********
: I = 14 J = 22
7:12:26 PM : ******** MATCH FOUND ********
: I = 15 J = 43
: ******** MATCH FOUND ********
: I = 16 J = 19
: ******** MATCH FOUND ********
: I = 16 J = 23
: ******** MATCH FOUND ********
: I = 17 J = 21
: ******** MATCH FOUND ********
: I = 18 J = 20
7:12:27 PM : ******** MATCH FOUND ********
: I = 19 J = 23
7:12:28 PM : ******** MATCH FOUND ********
: I = 24 J = 31
7:12:29 PM : ******** MATCH FOUND ********
: I = 26 J = 27
: ******** MATCH FOUND ********
: I = 28 J = 33
7:12:32 PM : Done and Dusted
: ABOUT TO STOP RUNNING TIME
: RUNNING TIME IS NOW: False
7:1

Any ideas?

Regards

If the thread isn’t doing anything other than acting as a timer, just use a timer.

Hi Clifford.

Thank you for the response.

The reason I am using a thread as a timer is I have the program doing processor heavy work. If I try to do it with a timer, my program doesn’t update until after the work has been completed.

Regards

AddUserInterfaceUpdate uses a Timer internally.

Have you tried using Thread.YieldToNext() instead of Thead.SleepCurrent(1000)?

Are you using preemptive threads?

So is the “processor heavy work” going on in the main thread? This sounds backwards to me.

Thanks Andrew.

I’m getting so many good hints.

Thank you.

I will try and advise.

Regards

Yes, Eric.

Thanks for the response.

Regards

why its not
var runTimerValue as integer = 0

i made a test and it ticks every second and update the UI, but i not waited until 10000 secods.
i chaged the sleep to few ms and it count to 10000.

if ui not get updates maybe a other running method blocks the main event loop.

in the UserInterfaceUpdate you could output if the event comes in
by look at the messages window in the IDE.

Var d As DateTime = DateTime.Now
System.DebugLog CurrentMethodName + " " + d.ToString

Thanks Marcus.

I’ll try this.

I set the runtimerValue to static so that it wouldn’t revert to 0 at every run.

Can you show me what you attempted (ie post your project) so I can look at it?

If not, it is totally fine.

Have a great day.

Regards

First thing I would try is Me.Sleep(1000) instead of Thread.SleepCurrent(1000) since you have a reference to the thread instance. There is no good reason to call the shared method version in this case.

But I agree with the others, your approach sounds backwards. Threads should be used for the heavy work so the main thread can keep the UI responsive. Doing the heavy work in the main thread and trying to use a thread as a timer isn’t really going to work since you still need the main thread to actually show the progress.

That’s where I would start my refactoring. I do not recommend preemptive threads, at least not at this stage. They’re a fantastic way to shave a few years off your life expectancy due to stress. Cooperative threads will take you a long way in most workloads. And if not, come on back and we’ll help you with workers and/or preemptive threads.

Thank you for the response, Thom.

A question however. How do i set the priority of the main thread.

When I create the other threads, I can set their priority. And set them as pre-emptive or cooperative.

Now a quick update (?)

I created a very simple project 1 button, 1 label, 1 thread, 1 timer and it works perfectly with this code:

In the button.Press

app.runningTime = TRUE

Window1.Thread1.Start

System.DebugLog "Button pressed"

// for testing only
System.DebugLog "The thread has been started"


In the thread.run

static runTimerValue as Integer

while app.runningTime = TRUE

runTimerValue = runTimerValue + 1

Me.AddUserInterfaceUpdate("timeCounter":runTimerValue)

Thread.SleepCurrent(1000)

wend


In the thread.UserInterfaceUpdate:

Var seconds As Integer

For Each arg As Dictionary In data

If arg.HasKey("timeCounter") Then
seconds = arg.Value("timeCounter")
Label1.Text = seconds.ToString
End If

next


In my timer.run

Thread1.Resume

And it works perfectly.

As a note / notes:

I have to use a static variable in thread.run, or the value of the variable resets every time the thread runs.

And the reason I use the threads is because BEFORE I did this in my real program, the UI for the progam did indeed become unresponsive (or gave the illusion). The program ran, finished cleanly, but I hated the fact that I couldn’t do anything with the window.

Regards

explained when the ui updates do his job (without a thread)
means if you are inside of a method the ui update do not work,
it will called after your method is finished
this main event loop is hidden and handled by xojo framework.
Anyway, I can explain the process and the behavior to myself.

do
 ui update
 dosomething
loop

function dosomething
 do something longer
end function

with a thread it is different
in its run event it can do something as long as you want because its interrupted by the xojo framework to do something else and update the UI, and later the thread continue.
that is the reason you put this dosomething longer method in a thread and start it there.

The main thread is locked to priority 5. What is your worker thread doing? Cooperative threads yield at loop boundaries, so if you’re making a plugin or other call that does not itself yield, a separate thread will not help.

Your code sounds more complicated than it needs to be though. On your window you should have a button, a timer, a thread, and a property. The button will start the timer, thread, and clear the counter. The thread does its work. The property stores the counter. The timer increments the counter and updates the label. Use a UserInterfaceUpdate at the end of the thread to signal when the work is complete so you can update the UI accordingly, such as stopping the timer. That’s really all there is to it. If your UI locks up when built this way, it means your work thread isn’t yielding any time to other threads. That’s the true problem that needs to be solved.

Without knowing what the work thread is doing, it’s impossible to suggest a solution. It could need some explicit yield or sleep statements, it could need to be a worker, or maybe even a preemptive thread.

This sounds like a bug I saw in 2024R3.1, I thought they had fixed it by 2025R2 but maybe not?
https://tracker.xojo.com/xojoinc/xojo/-/work_items/77567

Thanks to everyone who helped. I found the problem, though I have NO idea why this worked.

In my threadForRunningTimer, all I had to do was change Pre-emptive to Collaborative.

If anyone can explain why that worked (and I know in one of the many test iteratives of the program I created I did do that) I’m willing to be educated.

Once again thanks to everyone who helped.

Regards

I still hope you’ve not disregarded the advice you got in this thread. Your main thread should do the minimal work and a secondary thread should be where most of the work is done.
I have the impression you have tried to solve your problem while continuing in the same wrong way, and that’s not going to work in the end. Always better to refactor earlier rather than when all seems done and you’re finally forced to refactor way more than you could have done.

This is confusing, because what you report sounds exactly like this bug: https://tracker.xojo.com/xojoinc/xojo/-/work_items/77567
But that should have been fixed before version 2025R2.

Are you 100% sure you are using 2025R2 ? Perhaps you found another way to trigger the bug?

This is because a cooperative thread yields to other threads (including the main one) when it can, like between iterations of a loop. I wonder, though, whether you saw the difference when debugging in the IDE; last I knew, all threads are cooperative in the IDE, and you only see the difference in a built app.

Respectfully, though, per my earlier comment and in agreement with Arnaud, it sure sounds like your approach is backwards, and will give you maintenance problems in the future.

That is not true.