Thread kill event

Anyone know why there is no event for a thread when it is being killed? It would be useful to have that, so a thread can tidy up before it exits, possibly with the option to prevent the kill.

From experience I would say don’t kill your threads. Instead, use some kind of flag property on the thread so that they exit cleanly.

Yes, I thought about that. But then I have to check the flag all over the place. Also, I suspect that if the thread is suspended or on a sleep when it is killed, it dies without further ado. No chance to check the flag and tidy up in that case.

I have threads that may well be in that state when the user closes a window and I need the threads to cease.

In your thread subclass, you could:

  1. Make an Event Definition named Killed
  2. Override the Thread.Kill method With

raiseEvent Killed Super.Kill

Ah. I’ll have to look into it, I’ve not tried doing that. Thanks.

The only addition I’d make to Greg’s excellent advice is check to see if the call was made from a Thread (the same or another). If so, raise the event though a Timer.

Could you explain the need for this? Thx.

Sure. When you use RaiseEvent, the event is raised from whatever thread made that call. In this case, if you were to call Thread1.Kill from Thread2 or even from Thread1, the event would be raised within the context of that Thread and would restrict you from doing any UI work within it. Since Timer actions are always in the Main Thread, using a Timer to raise an event is the way to guarantee that the event is also raised on the Main Thread.

Thanks. Now you mention that, I recall seeing similar comments elsewhere on the forum.

I also see from the docs, if I have read them correctly, that if I add a kill method to my thread subclass (which is in fact just a modified version of the Task subclass), then it has to have the same parameters as the super’s kill (i.e. none as super.kill() has none). Does disregarding this prevent it overriding the super’s kill?

Yes, you would then have two versions of the Kill method, one with parameters and one without, but there is a workaround. Add a Kill (no params) method to your subclass and make it private. Have it call super.Kill to be on the safe side so you can still call it within the subclass. Then add your Kill (with params) method. Publicly, you will only be able to call Kill(params).

When threads are killed, a ThreadEndException is raised. This can also be a good way of having a thread clean itself up - just be sure to raise the exception again so the thread actually dies. Page Not Found — Xojo documentation

Hmm, first I’ve heard of this. The link you gave seems to be the only reference, it’s not mentioned in the list of exceptions (uh-oh, now I see it there) Presumably if it needs to be raised again if caught, then that also applies to to my app.UnhandledException event handler.

There have been discussions about the risk of using catch-all exception blocks for this reason - ThreadEndException is one that needs to be handled specially.

    catch e as NilObjectException // this will catch only one kind of exception
      ...
    catch e   // this will catch all exceptions, including  ThreadEndException (probably not what you want)
      ...

And there’s another gotcha to be careful of:

    catch NilObjectException // this will catch all exceptions, and the exception variable is named "NilObjectException" - danger!
      ...

ThreadEndException AND EndException should be handled specially and re-raised if caught. (The latter is for when the app is quitting.)

Do I need to do that inside my app.UnhandledException event handler?

No, EndException and ThreadEndException are never “unhandled”. Where you need it is in Try/Catch blocks that traps RuntimeException.

try
  // Code that might raise an exception
catch err as RuntimeException
  if err isa EndException or err isa ThreadEndException then
    raise err
  end if
  
  // Process the exception otherwise
end try

Obviously if you are catching a specific type of exception, you don’t need that.

OK - so it seems I can stop worrying about it in my app.UnhandledException event handler.

I also have only the one try/catch in my app:

catch e as IOException

so it sounds like I’m OK there too.

But it also sounds like it works like this: if a thread ends - and I assume this means ends normally as well as by being killed - then an exception is generated which lurks around doing nothing until some time later some bit of code does a try/catch. At which point unless the catch block contains the test you mention above, there may be trouble. Is this a fair summary?

I don’t think the exception is raised when the thread ends normally, just on kill, but I haven’t tested that.

Otherwise, no, the exception doesn’t “lurk”, it goes up the chain so the framework can handle it. A generic try/catch block without that check would get in the way of that process and keep the thread from being cleaned up properly.

Ah. That makes more sense. So a try/catch would have to be in progress at the moment of the exception. Mmm. Thanks.