views:

173

answers:

3

Hi all,

I have a pretty serious multithreaded debugging problem. I have some kind of timing issue when interacting with a serial device, and I need to track it down. I have three threads:

  1. The main thread for UI updates. The user can either change one parameter of the device, or many all at once by choosing a preset.
  2. The status checking thread that queries to make sure that the device is still attached. If the user shuts off the device or the device itself is interacted with in an interesting way, the status changes need to be reflected in the UI.
  3. The thread that reads the serial port where the device responds.

My problem actually has to do with debugging this situation. It seems like every single line I have in each thread has to have a breakpoint in order to be debugged; if I break in one thread, the debugger won't step through that thread. I understand that the other threads will continue to update, but shouldn't the thread I'm on execute like normal in the debugger, ie, go from one line to the next? Then, I could use the 'threads' tab to switch between threads.

I mention that I'm in WPF because I don't know if that changes the situation at all; maybe it does, maybe it doesn't. The status checking thread is part of a UI control, because the status needs to only be checked while the UI is up. That control is in a library distinct from the main application.

+5  A: 

When the debugger stops on a breakpoint, by default it will suspend all other threads. But when you step or continue all 3 threads are resumed. When you step through code, the debugger basically sets a temporary breakpoint on the next line and resumes all the threads. The other 2 may get a chance to run before that virtual break point is hit.

You can Freeze the other threads while debugging

When you're at a breakpoint select Debug | Windows | Threads. Select the threads you aren't interested in and right-click, select Freeze. This will let you focus on the one thread you're stepping through.

Paul Alexander
but my point is that it's not hitting that temporary breakpoint; it's just continuing blithely along, hitting no breakpoints other than the original one. I want the other threads to be running; I want to be able to see where they misbehave.
mmr
What happens when you manually break after stepping? Is it lost in a Win32 method somewhere or does it actually stop at some point later in your code?
Paul Alexander
it never stops, it just keeps on going.
mmr
Sounds like you've got a hosed VS install. Try running from another machine to see if shows the same behavior.
Paul Alexander
+1  A: 

If your code is single stepping in a weird manner, it can sometimes be caused by a simple broken pdb file. A "rebuild all" on your code will regenerate it from scratch and cure any such glitches.

Another thing to bear in mind is that stopping one thread in the debugger can cause all kinds of unusual timing that you wouldn't see in a release build. For example:

  • the Serial port will always continue to operate (on a hardware/driver level) while you have stopped on a breakpoint - when you next try to step your code, it can receive a sudden huge burst of data. With async callbacks this can be "interesting".

  • Stopping one thread disturbs the normal timeslicing so that thread to thread synchronisation can get screwed up.

Jason Williams
A: 

I'm with Jason, stepping won't show the truth anymore.

You're really better off instrumenting each line of code with a method that also increments a counter using Interlocked.Increment and adds the counter to the output (a local file is best).

The counter is needed because the order of actual events is not always the same as the order of writes to the file. Name the threads or use the ID value in the output, too. I use MS Excel to open the file and color all rows depending upon the thread, this way I can see the interleaving operations very clearly.

I have even written a wrapper to lock {} which instruments as each lock goes on/off.

Synchro problems are horrific to t-shoot so I advise not spending more than it would take to refactor. Sometimes its an indication that the approach you're taking is sub-optimal.

Remember to use volatile where necessary with IO.

Luke Puplett