一个超经典 WinForm 卡死问题的再反思( 二 )

  1. 工作线程ID 会记录在内部的 destinationThreadRef 字段中 , 我们试探下 02d69164
0:000:x86> !do 02d69164Name:System.Windows.Forms.WindowsFormsSynchronizationContextFields:MTFieldOffsetType VTAttrValue Name...533c220440025228 ...ows.Forms.Control0 instance 02d69218 controlToSendTo5cef92d04002523c System.WeakReference0 instance 02d69178 destinationThreadRef0:000:x86> !DumpObj /d 02d69178Name:System.WeakReferenceMethodTable: 5cef92d0EEClass:5cabf0ccSize:12(0xc) bytesFile:C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dllFields:MTFieldOffsetType VTAttrValue Name5cee2bdc400070a4System.IntPtr1 instance111828 m_handle0:000:x86> !do poi(111828)Name:System.Threading.ThreadFields:MTFieldOffsetType VTAttrValue Name5cee163840018ca28System.Int321 instance9 m_ManagedThreadId...从上面的输出中可以看到,9号线程 曾经创建了不该创建的 Control,所以找出这个 Control 就是解决问题的关键 , 这也是最难的 。
3. 如何找到问题 Control以我目前的技术实力,从 dump 中确实找不到,但我可以运行时监测 , 突破点就是一旦这个 Control 在工作线程中创建,底层会安排一个 WindowsFormsSynchronizationContext 以及 MarshalingControl 对象,我们拦截他们的生成构造就好了 。
为了方便讲述,先上一段测试代码,在 backgroundWorker1_DoWork 方法中创建一个 Button 控件 。
namespace WindowsFormsApp1{public partial class Form1 : Form{public Form1(){InitializeComponent();}private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e){Button btn = new Button();}private void Form1_Load(object sender, EventArgs e){}private void button1_Click(object sender, EventArgs e){backgroundWorker1.RunWorkerAsync();}}}接下来在 MarshalingControl 的构造函数上下一个bp断点来自动化记录 , 观察 new Button 的时候是否命中 。
0:007> !name2ee System_Windows_Forms_ni System.Windows.Forms.Application+MarshalingControl..ctorModule:5b9b1000Assembly:System.Windows.Forms.dllToken:0600554aMethodDesc:5b9fe594Name:System.Windows.Forms.Application+MarshalingControl..ctor()JITTED Code Address: 5bb5d1a40:007> bp 5bb5d1a4 "!clrstack; gc"0:007> gOS Thread Id: 0x249c (9)Child SPIP Call Site067ff2f0 5bb5d1a4 System.Windows.Forms.Application+MarshalingControl..ctor()067ff2f4 5bb70224 System.Windows.Forms.Application+ThreadContext.get_MarshalingControl()067ff324 5bb6fe5d System.Windows.Forms.WindowsFormsSynchronizationContext..ctor()067ff338 5bb6fd4d System.Windows.Forms.WindowsFormsSynchronizationContext.InstallIfNeeded()067ff364 5bb6e9a0 System.Windows.Forms.Control..ctor(Boolean)067ff41c 5bbcd5cc System.Windows.Forms.ButtonBase..ctor()067ff428 5bbcd531 System.Windows.Forms.Button..ctor()067ff434 02342500 WindowsFormsApp1.Form1.backgroundWorker1_DoWork(System.Object, System.ComponentModel.DoWorkEventArgs)067ff488 630ee649 System.ComponentModel.BackgroundWorker.OnDoWork(System.ComponentModel.DoWorkEventArgs) [f:\dd\NDP\fx\src\compmod\system\componentmodel\BackgroundWorker.cs @ 107]067ff49c 630ee55d System.ComponentModel.BackgroundWorker.WorkerThreadStart(System.Object) [f:\dd\NDP\fx\src\compmod\system\componentmodel\BackgroundWorker.cs @ 245]067ff6a0 7c69f036 [HelperMethodFrame_PROTECTOBJ: 067ff6a0] System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr, System.Object[], System.Object, System.Object[] ByRef)067ff95c 6197c82c System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(System.Runtime.Remoting.Messaging.IMessage, System.Runtime.Remoting.Messaging.IMessageSink)067ff9b0 61978274 System.Runtime.Remoting.Proxies.AgileAsyncWorkerItem.DoAsyncCall() [f:\dd\ndp\clr\src\BCL\system\runtime\remoting\remotingproxy.cs @ 760]067ff9bc 61978238 System.Runtime.Remoting.Proxies.AgileAsyncWorkerItem.ThreadPoolCallBack(System.Object) [f:\dd\ndp\clr\src\BCL\system\runtime\remoting\remotingproxy.cs @ 753]067ff9c0 6104e7b4 System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object) [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 1274]067ff9c8 61078604 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 980]067ffa34 61078537 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 928]067ffa48 6104f445 System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 1252]067ffa5c 6104eb7d System.Threading.ThreadPoolWorkQueue.Dispatch() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 820]067ffaac 6104e9db System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 1161]067ffccc 7c69f036 [DebuggerU2MCatchHandlerFrame: 067ffccc]

推荐阅读