Beginners question on threading

I'll add a tip that can be usefull while debugging. While running your application, under the Debug -> Windows a lot of items are available. One of them is Threads (default key combo: ctrl + alt + H).

Open this window.

When your program is paused (e.g. on a breakpoint or just stepping through some code), you can view all the active threads in your application in that window. If the Location of a thread is somewhere in your code, you can double click on that line, and the debugger will show the exact location of where that thread is at that moment, that way you can view what all the different threads are doing.
In most cases this is the easiest way to spot a deadlock or a situation like it seems to be in the code you posted above. When debugging the current code you should see 1 thread inside the loop, and other threads in the same function, but waiting for the SyncLock.

Good luck ;).
 
thanks for the info.. I went in and did a ctrl + alt + H and the threads window came up.. but I'm trying to go through the menu's and don't see where you open it up from if you want to see what all else is there to view.. can you point me in the right direction

I also took out the synclock.. and that got the looping to work.. got a lot to play with and learn about.. so once I do.. I'll have more questions.. hopefully you'll still be around to explain.
thanks
shannon
 
Last edited:
The menu is in under Debug->Windows (top item in the debug menu). But for some reason the list at development time has only 2 items (breakpoints and immediate) , but at run time there are about 10 of them, including the watches (1-4 and auto), call stack, threads, modules, memory, registers, all the fun things you really wish you'd knew how they work ;).

Be carefull though. If you only took out the synclock, you can have two threads calling the Counter = oCounter.NextValue at the same time, giving strange results (e.g. you skip 1 value of counter, and use another one by 2 threads at the same time). Especially as Counter is a member variable of the class and can be accessed by all the threads running.
If you only use that counter inside the while loop, it is saver to declare the counter inside the GetPerfmon method. Variables declared inside a method are always thread safe as another thread executing the same method, has its own instance of that variable. Member variables of classes however will always need protection as they can be accessed by all threads.

Here is an experiment you might want to try (I'm assuming the current code, and at least 2 threads running the while loop).
Put a breakpoint on the Counter = oCounter.NextValue and run the code. When the breakpoint hits, let the code proceed one line so the Counter value is updated, but don't execute the Debug.WriteLine yet (Use F10 to execute a single line). Do look up the current value of the Counter and write it down somewhere.
Now go into the thread window, and Freeze (right mouse menu) the current thread. Press F5 to let the program run again (the frozen thread is still paused and won't run yet).
What should happen now is that the thread remains frozen, and another thread will hit the breakpoin on the Counter = oCounter.NextValue line. Let this line execute, and let this thread execute the debug.writeline. Now go back into the thread window and Thaw (right mouse menu again ;) ) the thread you frozen earlier. Switch to this thread (also right mouse menu), and let it execute the debug.writeline statement.
Instead of the original value of Counter the frozen/thawed threat got when it did Counter = oCounter.NextValue (you did write it down I hope ;) ), it now has the same value as the other thread.
It is a bloody pain to reproduce, but race-conditions like these create the weirdest bugs you'll ever find as they are almost impossible to reproduce without spending hours on all possible timing scenario's.

One nasty thing about debugging multithreaded applications, if threads are running at the same time, the debugger can switch over from one thread to another without telling you, putting you in a different location of the code without warning, keep a close eye on what thread you are looking in when debugging like that, it is very easy to get confused. Especially when using a sleep command there is a high chance of a thread switch (with sleep it is 100% chance I believe ;) )
 
so if the sleep command is a high threat for thread switch.. and I want the thread to wait for several seconds before it runs again.. what are my options that would make it thread safe.
 
The sleep itself is perfectly thread save, however there is a threat switch when you sleep. A threat switch in itself is perfectly OK, the OS does them and you can't prevent it even if you wanted to, maybe I wasn't clear about that.

What must be done is making the rest of the code safe to correctly handle that all member variables can be accessed from two different threads at (virtually, see bellow) the same time if they arent protected. That means that yes, you have limit the actual reading/writing of member variables and make sure only 1 thread at a time can do that. However, make the blocking as small as possible so you block as little as possible or you might run into the problem you had before.

Note that when a thread encounters a lock that it can't pass yet (another thread has it), the OS automatically switches to another thread, leaving the original thread at the lock statement.


You said you removed the SyncLock. What I ment in my reply is: if you don't implement a locking mechanism at all, you will run into a lot of problems.
Sadly multithreading isnt something you can trial and error until everything is fixed, as you will keep running into problems, some only appearing after 4 hours of execution or worse, after the customer started using it.
You really have to look at how all the variables that can be shared between threads (like the member variables in a class) are accessed, and how to protect access to it, with the smallest scope possible. You need to use a locking mechanism (like SyncLock, or a critical section like the ReaderWriterLock) to make sure no 2 threads have access at the same time, but you also need to use it as little as possible to prevent other problems.

I think nobody ever claimed multithreading was easier than very difficult. The concepts of multithreading (having 2 or more threads do the same thing at the same time and how to protect everything) are very hard to get a grip on. I've had quite some experience with multithreading in c++, and those concepts of threads, locks, etc still apply to .NET, but in c++ it took me about a year to get a good grip on the basic principles of having your code execute in two locations at the same time and how to protect your application against problems resulting from this.
The .NET framework might make using threads and everything easier, however, the concepts behind them are still just as difficult. Don't try using multithreading just because you want a checkmark on a feature list. The amount of work it takes to get it right is rarely worth the extra feature. Only use it when you have no other option.


On the virtually remark I made above:
With virtually I mean that with a (old fashioned, pre-Intel hyperthreading) single CPU, the CPU can execute only 1 assembly statement at a time, but assigning a value to a parameter (single line of code in the editor) can be several lines of assembly. So dont assume that 1 line of code is always run without a thread switch half way the line of code.
 
I had turned to the multithreading because I had written a little perfmon utilty that recorded performance monitor data to a sql server. some of the perfmon counters have to be run twice before they will report correct information... so I had created a console app that spawned off other console apps to record the data. I thought if I could get a multi threaded app to work..it would be a cleaner approach.. I'm a sql guy by trade.. so watching locks in sql and coding against getting them but keeping transaction soild I understand.. this vb world is new and getting the best of me. :)
 
Back
Top