views:

180

answers:

6

Hi all,

I have a deadlock when I invoke the UI thread from a worker thread. Indeed, the worker thread is blocked on the invoke line:

return (ucAvancementTrtFamille)mInterfaceTraitement.Invoke(d, new object[] { psFamille });

The weird thing is that the UI Thread (which, correct me if I'm wrong, is the main thread) is idle.

Is there any way to:

  1. see which thread I'm actually trying to invoke?
  2. see what said thread is really doing?

We can see in the image below, the worker thread (ID 3732) blocked on the Invoke line, and the MainThread is idle in the main function of the application.

alt text

Edit: Here is the stack of the main thread:

alt text

Edit2: Actually, I paused the the program a second time, and here is what the stack looks like:

alt text

Edit3: Workaround found

I finally found a workaround. The problem is apparently due to an async wrapper race condition issue. The workaround is to use BeginInvoke and wait for it with a timeout. When it times out, invoke it again and loop until it finally returns. Most of the time, it actually works on the second call.

IAsyncResult ar = mInterfaceTraitement.BeginInvoke(d, new object[] { psFamille });
            while (!ar.AsyncWaitHandle.WaitOne(3000, false))
            {
                ar = mInterfaceTraitement.BeginInvoke(d, new object[] { psFamille });
            }
            // Async call has returned - get response
            ucAvancementTrtFamille mucAvancementTrtFamille = (ucAvancementTrtFamille)mInterfaceTraitement.EndInvoke(ar);

It's not pretty but it's the only solution I found.

A: 

Have you tried using BeginInvoke instead of Invoke? BeginInvoke is asynchronous.

SimpleCoder
but Invoke should work
Andrey
Yes but `BeginInvoke` doesn't block the caller. It's just a suggestion, although yes, it shouldn't matter.
SimpleCoder
SimpleCoder, the OP wants a return values from the Invoke. BeginInvoke can't just replace here.
Henk Holterman
A: 

Have you tried using a BackgroundWorker instead. If you use it it will save you a lot of this.Invoke and InvokeRequired calls.
I believe that if you create a new thread and make it execute the line you are showing you won't have a deadlock. I will try find old code of mine and post it here.

sh_kamalh
+3  A: 

The Main thread doesn't look idle. Your screen shot shows it current location at ECM.Program.Main. That can't be correct, if it is idle then it is inside Application.Run(), pumping the message loop. Which is required for Invoke() to complete.

Double-click the main thread and switch to the Call Stack window to find out what it is really doing.

Hans Passant
Well, you are right: it is in Application.Run(), which is in my ECM.Program.Main. See my edit: it shows the stack of the main thread.
leo
Yes, looks like it is pumping to me as well. Rough. Setup the Symbol Server, enable unmanaged code debugging and show us the call stack of the deadlocked thread.
Hans Passant
It seems that the async wrapper has a race condition issue. See my third edit with the workaround I found.
leo
+2  A: 

You are correct. The Main Thread is the entry point to the application which is normally the location of the call to Application.Run which gets the message loop going. So that should be the UI thread unless you have done something out of the ordinary in regards to the message loop which is unlikely.

In the Thread window you can right click on the Main Thread and select Switch to change the debugging context to that thread. The Call Stack window will then show the location of the current executing method.

If your worker thread really is blocked on the Control.Invoke call and the UI thread is idle as you claim then the problem could be with the execution of the instructions within the delegate that is being marshaled or the message loop as not yet been started. The later seems plausible since your screen shows the location of the Main Thread as Main.

Brian Gideon
I'm editing my question, and adding the stack of the main thread. I've enabled the option "Show External Code".
leo
A: 

Is there any way to:

  1. see which thread I'm actually trying to invoke?

  2. see what said thread is really doing?

The answer to both is yes.

First you'll need to get a full memory dump. You can that in Vista and windows 7 using the task manager (although I've never tried it) or ProcDump or debug diag. There's probably other alternatives as well.

Then you can load the memory dump into WinDbg which will enable to find exactly what thread you're trying to invoke and see what the thread is really doing.

Please note this is no mean feat. WinDbg has fairly cryptic commands and it requires a lot of patience, but when you want the answers to the above there's not much else.

If you've never used WinDbg before you might want to take a look at this post

If you want to see a walk through of an analysis of a hang take a look at this post

Conrad Frix
A: 

Hi,

Are you using Visual Studio 2008 ? If the answer is yes, you should try with Visual Studio 2010. It's a known bug.

Good luck !

Bastien D