I’m finding that simply running simultaneous endless loops turns up the error. Below is an example. Any thoughts on what’s going on and how to avoid it?
Protected Overrides Function RunCommand(ByVal doc As RhinoDoc, ByVal mode As RunMode) As Result
'create list of threads
Dim ThreadList As New List(Of System.Threading.Thread)
For i = 0 To 5
ThreadList.Add(New System.Threading.Thread(AddressOf Looper))
For i = 0 To 5
For i = 0 To 5
Commands aren’t run in a separate thread, they block until the are done.
You create five threads, then wait for them to complete through the Join() call. This means Rhino will keep blocking until your threads join.
If you don’t Join() you 'll see the threads keep on running. You’ll also find that your command returns right after the threads have been started. That may or may not what you’re after, but you’ll have to be very careful in how you create your code with such a set up. You’ll most definitely open up a big can of worms.
I’m surprised the commands return right after the threads have been started. Shouldn’t the command wait until the code has finished? Perhaps this is what is causing the “other program is busy” error. Is there some way to prevent this from happening and if so how can I change the code?
Your current code is not returning right away. Because you are joining your threads the command won’t return until your threads are done. You said your threads are always running, i.e. never returning, your command will be waiting forever for your threads.
You need to ensure your threads exit at some point, allowing them to join.
What I tried to suggest in the earlier post is that you don’t call the join on your threads, but that is going to put you in a tricky situation. Ensuring your threads have a good exit condition is probably the best thing to do.
My threads do return eventually. I was only using the infinite loop to demonstrate that, after some period of time, the “busy program” error pops up. I’m thinking it is because my threads are long that I get this error rather than because I’ve missed a spot where I’m accessing UI elements (I’ve gone through my code many times to eliminate this).
You had originally said accessing UI elements would cause the “busy program” error. But you see what I mean that simultaneous threads with endless loops also trigger the error? Perhaps there is some way to suppress the error? Any suggestions?
So it is working now, though I’m getting inconsistent runtimes: When running three similar simultaneous threads, sometimes they all finish quickly, much quicker than running them without multithreading. However, sometimes the last thread will drag on for a long time. Could this be related to the OleAlerts being suppressed but still slowing things down or can you think of another possible cause?
Welcome to multithreading. Exact timing is much less consistent when multithreading. It’s like when you have 6 people doing one task. Cooperation might be difficult and there might be resource contention.
We all did several tests on multithreading and I’ve never seen anything above a few ms when the model was correct. There must be something else going on. I never used thread.Join, though, because performing SendMessage and COM task right in that place was never a good idea for me. Why do you need them there?
Each thread is a simulation and I have to wait until all of them are done until I can summarize the results. If Join is what is causing the problem, perhaps you have another suggest for how to run code only after all threads have finished?
Update: I’ve tried it without the Join statement (so no summarizing at end) and it still seems to take (sometimes) much longer than single thread. So I don’t think the Join statement is the issue. Any other thoughts?
Maybe the easiest for this simpler task is to avoid manually messing with threads entirely and use Parallel.ForEach. This allows to leverage the ThreadPool and let the runtime decide when to multithread. Also, creating a new Thread might not always be required. I do not know all requirements.
I would recommend using a GetString class with a SetWaitDuration of around half a second. This way the UI can stay alive and the user can cancel. When the wait duration has completed, you can see if your threads are complete and if not run the Get() again in a loop. This is pretty much what we do in V6 with geometry calculations that are running on multiple background threads.
I gave that a try and it did seem to be working earlier today, most of the time, but now it’s not. This multi threading business is oddly inconsistent. I think I’m going to have to put this on hold for a bit to catch up on some other things.
I really appreciate the supports, extremely helpful as always!