12

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.

svick
  • 236,525
  • 50
  • 385
  • 514
leo
  • 1,134
  • 1
  • 8
  • 20

5 Answers5

5

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
  • 922,412
  • 146
  • 1,693
  • 2,536
  • 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 Sep 22 '10 at 07:33
  • 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 Sep 22 '10 at 12:02
  • It seems that the async wrapper has a race condition issue. See my third edit with the workaround I found. – leo Sep 23 '10 at 09:09
2

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

Chris Laplante
  • 29,338
  • 17
  • 103
  • 134
  • Yes but `BeginInvoke` doesn't block the caller. It's just a suggestion, although yes, it shouldn't matter. – Chris Laplante Sep 21 '10 at 16:58
  • 1
    SimpleCoder, the OP wants a return values from the Invoke. BeginInvoke can't just replace here. – H H Sep 21 '10 at 17:47
2

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
  • 47,849
  • 13
  • 107
  • 150
  • I'm editing my question, and adding the stack of the main thread. I've enabled the option "Show External Code". – leo Sep 22 '10 at 07:36
0

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,853
  • 4
  • 38
  • 50
0

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 !