Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deadlock when invoking the UI thread from a worker thread

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.

like image 746
leo Avatar asked Sep 21 '10 16:09

leo


3 Answers

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.

like image 146
Hans Passant Avatar answered Nov 07 '22 22:11

Hans Passant


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

like image 2
Chris Laplante Avatar answered Nov 07 '22 22:11

Chris Laplante


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.

like image 2
Brian Gideon Avatar answered Nov 07 '22 22:11

Brian Gideon