Odd Thread Accessing UI Exception Error

Hey all,

I don’t understand this one…

I’m getting a thread accessing UI exception, but I am not accessing a UI element when this occurs. I’m running Aaron Ballman’s thread pool manager code and sometimes, this exception happens, but not always. Here’s where it’s firing:

Sub Run()
// Tell the item that it’s about to do
// some work
mWorkItem.InitializeItem

// Now do our work
mWorkItem.DoWork

// Then finalize the work item
mWorkItem.WorkCompleted

// Remove our work item so that
// it can be destroyed properly
mWorkItem = nil
This line above is where the exception occurs…
End Sub

For those of you not familiar with Aaron’s code, mWorkItem is an object that has a specific interface with the IntiailizeItem, DoWork and WorkCompleted methods. The mWorkItem is NOT a UI object. It’s an object of type WorkItem which is the name of the interface.

Now some of my UI controls are Objects that have the WorkItem interface and I do use this to run threaded code. But the code never does any manipulation with the UI itself. And the exception is being raised not when I’m actually executing my DoWork method but when the mWorkItem object is being set to NIL.

Is this a bug? I don’t think it should be raising an exception…

And in fact, looking further in the stack, I see I have three threads running under the thread pool manager when this exception fires. All three of them show the AccessingUIFromThread exception. The other two threads are being slept. So how can sleeping a thread cause an AccessingUIFromThread exception?

Bug?

I’d be interested to know if it’s a Control or a Window:

[code]dim isControl, isWindow as boolean

isControl = (mWorkItem isa Control)
isWindow = (mWorkItem isa Window)
mWorkItem = nil
[/code]
If either of those are true and the mWorkItem is the last reference to the object, destroying the control or window might be expected to raise that exception. Also, if isControl or isWindow is true, then mWorkItem is a reference to a UI object. A UI object that implements the WorkItem interface.

Thanks, Brad. I can almost guarantee you that it’s a control. But mWorkitem is not the last reference to any control that would be passed Into it as I am not removing any controls from the window.

I suppose what I need to do is find out what control it is but I don’t know how to correct it as its not code being executed in a method of the control that’s the problem. I’ve made double and triple sure that anything that needs to manipulate the UI is done from timers in all my objects. Spent a lot of time doing that. Even raising events from timers. It’s gets hard as some events you want to happen in the context of the thread others you need in the main thread. But I am confident I have all that worked out as none of that is causing the error.

You should look at the exception’s stack property to see what the cause is.

I’m sorry, Joe, but where is that? I see the stack on the left and all I have is thread pool.event.run. If I pick other items from the list in the stack, I see other threads which are sleeping but which also show the same error. So I’m not sure. Where to find the stack property. I’ve looked under the exception item itself and all that is there is the error number and message.

Brain fart…,I’ve looked at the stack - just not viewable in the IDE. It tells me nothing. Let me try to find one of my saved copies and ill post it.

Here is one stack:

REALbasic._UITrap
Control.__Exit%%o
RuntimeIsEventHandled
RuntimeUnlockObject
RuntimeUnlockObject
RuntimeLockUnlockObjects
ThreadPoolThread.Event_Run%%o
threadRun
_pthread_start

Here is another:

REALbasic._UITrap
Window.Width.Get%i4%oi4
DebugRuntimeInit
BreakOnExceptions
BreakOnExceptions
NetworkWakeOnLAN
NetworkWakeOnLAN
NetworkWakeOnLAN
systemGetKeyChainCount
rnd
NetworkWakeOnLAN
DebugRuntimeInit
DebuggerHook
RuntimeDebuggerBreak
RuntimeBackgroundTask
ThreadPoolManager.Event_Run%%o
threadRun
_pthread_start

I don’t know why the window.width is being called here. I don’t access that in the thread. Not sure if that is a Xojo thing or not as there’s a bunch of Xojo stuff in there.

Put the code in a try/catch RuntimeException. When it catches, inspect the RuntimeException. It has a stack property.

OK. Let me try that…Because I just checked and I never pass a window into the thread and the control I do pass is a custom control but I’m not mucking with any UI parameters or objects. And if I was, that exception would be thrown during that code execution not when setting the object in the thread to Nil…

The only thing I can think of that might be happening is that these controls are all members of a control set. The first one gets instantiated on the page in the IDE. I believe I then close it. I just looked in my open event code and I invoke the thread from the open event. So it’s entirely possible that your comment, Brad, about setting the last reference to the object as nil might cause this could indeed be part of the problem. I’ll try your catch and then also look further in my code.

Boy, oh boy. I can’t wait for all the threads starting up on the NUG and the forums when Xojo launches and suddenly people get all these ThreadAccessingUI exceptions. It’s going to cause quite a stir!

Yeah, there is going to be a lot of “negotiating”. Hopefully, after 10 or 1000 rounds of negotiating, there will be enough evidence that negotiating doesn’t fix the underlying issue. Worst thing that can happen with this stuff is that we get an amalgamation of exceptions to the general rule.

Best thing that can happen is a 3rd party makes a “thread safe” control set that resolves the issue the obvious way, with Timers and message queues. The reason this is better than RS/Xojo doing it is that people who use the Thread model “correctly” shouldn’t get stuck with performance penalties needed to handhold those who don’t/can’t/won’t.

No. Still don’t see that.

If I do:

try
// Remove our work item so that
// it can be destroyed properly
mWorkItem = nil
catch
break
End try

The break never happens. The catch is ignored.

I have the app e-mail me whenever an unhandled exception occurs and that e-mail includes the exception message and the stack. Here it is from the one I just had:

ThreadAccessingUIException

A thread has attempted to manipulate a user interface element. This can only be done from the application’s main thread.

REALbasic._UITrap
Control.__Exit%%o
RuntimeIsEventHandled
RuntimeUnlockObject
RuntimeUnlockObject
RuntimeLockUnlockObjects
ThreadPoolThread.Event_Run%%o
threadRun
_pthread_start

So what is going on???

catch err as RuntimException x = 1 // <-- breakpoint here end try

[quote=7626:@Richard “Brad” Hutchings]catch err as RuntimException x = 1 // <-- breakpoint here end try[/quote]

Nope. The framework is not catching this error (perhaps that itself is a bug?):

try
// Remove our work item so that
// it can be destroyed properly
mWorkItem = nil
catch err as RuntimeException
dim x as integer = 1
End try

Completely skips the catch statement…

Wow, stumped.

I guess I shall file a bug report then. Shouldn’t be too hard to duplicate in a simple project…

I’m not sure why the catch block is not working. I tried doing this in a very simple test app with a thread and a control and the catch block worked as expected. I guess I’ll now have to look at adding in the thread pool class to see if that is causing an issue.

But the good news is that I think I have my original problem solved. Brad, you were correct when you stated that perhaps it was due to destroying the last reference to an object. That’s because I instantiate my control on the window in the IDE, I then close it and then rebuild my control group depending on saved user parameters. The problem was that the initial “0” instance was being passed to the thread in its open event and operations were being done. Then back in the main thread, that initial “0” instance was being closed. Some items in the thread could take several seconds to run and so the thread was continuing to run after the initial object was closed. So the object in the thread was the only remaining reference to that object. Once the thread set it to nil, then the thread was destroying a UI object and the exception being raised. Very obscure issue, but very insightful on Brad’s part.

I’ve solved this by checking to see if the container control that is holding my custom control is initialized and open before I pass the control to the thread. So I basically skip calling the thread when opening the very first initial instance of the control. When I run the method to create my controls, the container control is initialized and so the If/then statement in the open event of my custom control then allows me to call the thread…

[quote=7636:@Jon Ogden] So the object in the thread was the only remaining reference to that object. Once the thread set it to nil, then the thread was destroying a UI object and the exception being raised. Very obscure issue, but very insightful on Brad’s part.
I’ve solved this by checking to see if the container control that is holding my custom control is initialized and open before I pass the control to the thread. [/quote]

Could you instead use a WeakRef to the control in the Thread so the thread was never keeping an object alive beyond it’s expected lifespan?

That’s possible, but what happens if the control goes away while the thread is in the middle of executing a method of the control? Would that not possibly cause a crash as well. I would think that you should not want to start threaded operations until your window is up and initialized…

Still your point is a good one. A WeakRef may be better, but what happens if an operating is being performed on the object and it goes away. That’s my hesitancy…

Jon, you’d get a real reference from that WeakRef before working on it. If no reference, stop doing work. Just make sure you test that WeakRef every time the thread resumes, e.g. at the top of loops. Accounting is complicated, but should work.

Generally if you are in a thread, you know precisely(*) when the thread can or can not yield back to the other threads (which is a major benefit of cooperative, as opposed to Pre-emptive threading):

So in code like this

if myControlWeakRef <> nil and myControlWeakRef isa Control then
   dim r as RectControl(myControlWeakRef)
   r.foo()
   r.bar()
end if

you are guaranteed that the control will not disappear between Foo() and Bar() as long as neither Foo() nor Bar() yields.

(*) One of my pet peeves with the Framework is that there are a few odd places where the Framework itself yields internally - these are few and far between, not documented or predictable, but that’s a rant for another thread :slight_smile: