Basic Thread Management

I’m going to school here on threads and looking for suggestions. I’ve gone through everything I can find on threads here in the forum, the docs, example projects, and the threads webinar. It gets deep fast.

I’ve got an app. A timer kicks off a thread and it does some “stuff” every 15 minutes. To do all this might take 5 minutes on a heavy day.

What I found was that about once every 3-6 weeks, roughly, the thread would kick off and get the ThreadAlreadyRunning exception. I suppose I could catch that and handle it but no. I had to rework it all based on what I think I learned reviewing all the info on the subject. It turns out I don’t know as much as I think I do.

Right now I’ve got a thread object that gets created by the timer. Does this thread end on it’s own when it’s all done? If not then the app will be spawning new threads? How do I might I manage this?

Thanks!

Can we see the code in the Timer?

Well, if the thread leaves the running event it is no longer running. So you might want to add a check in the timer.action event to see if the state of the thread is running or not. If it is, you have a couple of options. You can kill the thread or just return (and let it complete).

You might want to double check code in the thread to see why it’s NOT completing. But since it’s sporadic it might take a while. You might need to do some logging to find it if it really happens so rarely.

The article by Aaron Ballman “Creating a Thread Pool” (available for free at http://xojolibrary.com/) could be helpful if your are looking for Thread management info.

This is an older app and my code is not in good form. It was a learning experience. It’s all in a twist now.

The timer coder calls a method that was my attempt at managing this. It’s basically cut and paste out of the example project.

Try Select Case mDataSync.State Case Thread.Running app.LogDataError("00101", "Thread is Running and Killed.") mDataSync.Kill Case Thread.Waiting app.LogDataError("00102", "Thread is Waiting.") Case Thread.Suspended app.LogDataError("00103", "Thread is Suspended.") Case Thread.Sleeping app.LogDataError("00104", "Thread is Sleeping.") Case Thread.NotRunning app.LogDataError("00105", "Thread is Not Running.") mDataSync = new DataSync mDataSync.run End Select Catch err as NilObjectException app.LogDataError("00105", "Thread is Not Running.") mDataSync = new DataSync mDataSync.run End Try

This method, named ManageThread, is called at the beginning and the end.

This sounds like a good suggestion to move the above code to the time.

That’s a big problem, or so it seems. I’ve got logging going on all over the place.

I have a button which starts a thread to check the Imap connection. Even with checking the state of the thread I had to add the try/catch because I occasionally got a ThreadAlreadyRunningException. Even though the structure of the code is very simple:

[quote] try
If ThreadCheckImap.State <> Thread.Running then
ThreadCheckImap.Run
else
ThreadCheckImap.Kill
end if

catch err as ThreadAlreadyRunningException
ThreadCheckImap.Kill
end try[/quote]

HTH

Are you initiating this thread from anywhere else?

There is a menu where the thread can be initiated manually. That doesn’t get used much except when there is a failure and the process gets behind or when testing changes to the code.

It seems to be working now but for some reason it’s running every 30 minutes instead of 15. There’s a flaw in the logic somewhere.

You might want to post the thread code too. If it can take that long to run, there might be room for optimization.

Part of the problem is that there is a lot of room for optimization. This is an early app for me and I also had to come to understand XML. It was quite befuddling. In order to complete the project I just forged ahead. It could go for a complete rewrite. But to answer your question there isn’t much code in the thread itself other than a call to the main routine located in a module. It’s a one liner. That code then calls other methods in the same module as well as the app.

Basically the app reaches out to a database and asks for new or changed contact records. It receives a list of keys and then loops through them getting the individual record data. All in XML. It then converts that to MySQL format and updates the local database. It also does this for events and event attendance.

So there’s a lot of code outside the thread in methods.

Since it’s called by the thread, that would count as the thread’s code.

How/why does it get the database records in XML?

Begin/End of what? The Timer? The Thread?

It should be called at the beginning of the timer. It doesn’t help to call it from the thread.

I would recommend you simplify the code to

if mDataSync = Thread.NotRunning then
   mDataSync.Run
else
   // do nothing and allow the thread to continue running
end

You might also consider putting mDataSync = Nil at the end of the thread Run event. Then the timer becomes

if mDataSync = Nil then
   mDataSync = New DataSync
   mDataSync.Run
else
   // Thread is running, do nothing and allow it to continue
end

It is first called from within the Timer and finally after the last line of code in the processing.

Good tip, that would be a better way to end the thread.

It wouldn’t so much end the thread as signal that the thread has ended.

At that point it should hit the Thread.Running case, since it is being called from within the thread, and Kill itself, which isn’t necessary as the thread is about to end anyway.

OK…this sorted out. I was looking at some unexpected results which threw me off. This is a new machine I’m running it on and I did not have it configured properly. It was going to sleep. So the timer wasn’t kicking off when it should.

It looks like it all works in the various versions I’ve posted. I’ll clean this up and wrap it up with another post.

Thanks for the suggestions everybody.