zoukankan      html  css  js  c++  java
  • 并发之阿喀琉斯之踵

    这两天线上OpenXml在并发的情况下Hang住了, 因为我之前还是对死锁有过深入的研究就自告奋勇的排查一下这个问题了. 但是最终发现这个不是普通的.NET死锁, 我把排查的辛路历程写一下供大家参考.(OpenXml使用到了独立存储)

    首先按照常规:

    1. 启动Windbg

    2. Ctrl+S设置一下Symbol Path, 我这里就指定为 SRV*c:mysymbol* http://msdl.microsoft.com/download/symbols

    3. 快捷键F6, Attach to Process , 选择要调试的应用程序.

    4. 加载.NET调试支持 .loadby sos clr (因为我这里是.NET环境)

    5. 因为怀疑是死锁.NET下有个sosex扩展中有专门检查死锁的命令, 因此为了省点力气就需要加载一下, 命令为 .load D:SoftCodeToolsDebugtoolssosex_32sosex.dll 具体下载地址可以访问http://www.stevestechspot.com/SOSEXV40NowAvailable.aspx

    6. 运行!dlk命令进行检查.

    0:005> !dlk
    Examining SyncBlocks…
    Scanning for ReaderWriterLock instances…
    Scanning for holders of ReaderWriterLock locks…
    Scanning for ReaderWriterLockSlim instances…
    Scanning for holders of ReaderWriterLockSlim locks…
    Examining CriticalSections…
    Scanning for threads waiting on SyncBlocks…
    Failed to retrieve frame. Error = 0×80070057.
    Scanning for threads waiting on ReaderWriterLock locks…
    Scanning for threads waiting on ReaderWriterLocksSlim locks…
    Scanning for threads waiting on CriticalSections…
    No deadlocks detected.

    显示结果,没有死锁, 很奇怪是不是. 没有办法先手工看一下.NET中的所有的同步块情况吧.

    7. 运行命令!SyncBlk –All 来获取

    0:005> !SyncBlk -All
    Index         SyncBlock MonitorHeld Recursion Owning Thread Info          SyncBlock Owner
    1 008f7834            0         0 00000000     none    02562038 System.Threading.Thread
    2 008f7868            0         0 00000000     none    02562118 System.Threading.Thread
    3 008f789c            0         0 00000000     none    025621a4 System.Threading.Thread
    4 008f78d0            0         0 00000000     none    0d110f7c System.BaseConfigHandler+NotifyEventCallback
    5 008f7904            0         0 00000000     none    02da8274 MS.Win32.ManifestEtw+EtwEnableCallback
    6 008f7938            0         0 00000000     none    02568774 Microsoft.Win32.UnsafeNativeMethods+ManifestEtw+EtwEnableCallback
    7 008f796c            0         0 00000000     none    0256ba14 Bid+CtrlCB
    8 008f79a0            3         1 008fc420 1e04   5   02db8f88 System.Object
    9 008f79d4            0         0 00000000     none    0d112fb4 System.BaseConfigHandler+BeginChildrenCallback
    10 008f7a08            0         0 00000000     none    0d112fd4 System.BaseConfigHandler+EndChildrenCallback
    11 008f7a3c            0         0 00000000     none    0d112ff4 System.BaseConfigHandler+ErrorCallback
    12 008f7a70            0         0 00000000     none    0d113014 System.BaseConfigHandler+CreateNodeCallback
    13 008f7aa4            0         0 00000000     none    0d113034 System.BaseConfigHandler+CreateAttributeCallback
    14 008f7ad8            3         1 008fc420 1e04   5   0d01aabc System.Object
    —————————–
    Total           14
    CCW             0
    RCW             0
    ComClassFactory 0
    Free            0

    加粗的部分描述了, 目前只有两个锁, 同时被线程5持有着. 按照这个逻辑的确是没有死锁. 只能进一步做检查, 看一下是不是非.NET代码导致的死锁.

    8. 进一步检查非托管代码的情况. 运行命令!locks -v检查所有的锁

    0:005> !locks -v

    CritSec ntdll!RtlpProcessHeapsListLock+0 at 77cfb7c0
    LockCount          NOT LOCKED
    RecursionCount     0
    OwningThread       0
    EntryCount         0
    ContentionCount    0

    CritSec +890248 at 00890248
    LockCount          NOT LOCKED
    RecursionCount     0
    OwningThread       0
    EntryCount         0
    ContentionCount    2b

    CritSec +680248 at 00680248
    LockCount          NOT LOCKED
    RecursionCount     0
    OwningThread       0
    EntryCount         0
    ContentionCount    0

    CritSec +810248 at 00810248
    LockCount          NOT LOCKED
    RecursionCount     0
    OwningThread       0
    EntryCount         0
    ContentionCount    0

    CritSec SspiCli!SecPackageListLock+0 at 756476b0
    LockCount          NOT LOCKED
    RecursionCount     0
    OwningThread       0
    EntryCount         0
    ContentionCount    0

    CritSec +670248 at 00670248
    LockCount          NOT LOCKED
    RecursionCount     0
    OwningThread       0
    EntryCount         0
    ContentionCount    0

    CritSec +2550248 at 02550248
    LockCount          NOT LOCKED
    RecursionCount     0
    OwningThread       0
    EntryCount         0
    ContentionCount    0

    CritSec ntdll!LdrpLoaderLock+0 at 77cfb790
    LockCount          NOT LOCKED
    RecursionCount     0
    OwningThread       0
    EntryCount         0
    ContentionCount    c

    CritSec +46c0248 at 046c0248
    LockCount          NOT LOCKED
    RecursionCount     0
    OwningThread       0
    EntryCount         0
    ContentionCount    0

    CritSec +8fc018 at 008fc018
    LockCount          NOT LOCKED
    RecursionCount     0
    OwningThread       0
    EntryCount         0
    ContentionCount    0

    CritSec ntmarta!gWrkrLock+0 at 7539e220
    LockCount          NOT LOCKED
    RecursionCount     0
    OwningThread       0
    EntryCount         0
    ContentionCount    0

    CritSec ntmarta!gCacheLock+0 at 7539e1e0
    LockCount          NOT LOCKED
    RecursionCount     0
    OwningThread       0
    EntryCount         0
    ContentionCount    0

    CritSec ntmarta!grgRightsNameCache+23c at 7539e290
    LockCount          NOT LOCKED
    RecursionCount     0
    OwningThread       0
    EntryCount         0
    ContentionCount    0

    CritSec ntmarta!grgRightsNameCache+324 at 7539e258
    LockCount          NOT LOCKED
    RecursionCount     0
    OwningThread       0
    EntryCount         0
    ContentionCount    0

    CritSec +4dd0248 at 04dd0248
    LockCount          NOT LOCKED
    RecursionCount     0
    OwningThread       0
    EntryCount         0
    ContentionCount    0

    CritSec SHELL32!g_lockObject+0 at 75d39ff8
    LockCount          NOT LOCKED
    RecursionCount     0
    OwningThread       0
    EntryCount         0
    ContentionCount    0

    Scanned 16 critical sections

    仅仅找到了16个临界区. 并且所有的都未被任何线程持有着. 这样也说明了是没有死锁的. 难道是孤立锁导致的? 我又重新运行Windbg, 这次不要用Attach的方式了, 直接Ctrl+E来运行这个Exe程序, 并添添加Main方法入口的断点. 同时设置CLR的异常断点, 经过我调试并没有发现任何线程异常抛出. 没有异常也就说不可能导致孤立锁的情况. 同时前面的锁信息也显示了不可能是孤立锁. 所以这个检查的意义不大, 是对自己思路的不自信导致的. 我百思不得其解了.

    我回家后深思了我目前的任何线索, 我还是决定重新排查一下,这次要结合源码来看.

    .net2.0就发布了shared-source-cli-2.0 跟线上.NET类库的代码http://referencesource.microsoft.com/

    那么我们重新开始吧

    1. 让我们看一下堆栈吧, 运行 ~*e!clrstack查看当前进程中所有的线程托管堆栈.

    0:005> ~*e!clrstack
    OS Thread Id: 0×2770 (0)
    Child SP       IP Call Site
    GetFrameContext failed: 1
    00000000 00000000 <unknown>
    OS Thread Id: 0x22dc (1)
    Unable to walk the managed stack. The current thread is likely not a
    managed thread. You can run !threads to get a list of managed threads in
    the process
    Failed to start stack walk: 80070057
    OS Thread Id: 0×2020 (2)
    Child SP       IP Call Site
    0252f638 77c3c1ac [DebuggerU2MCatchHandlerFrame: 0252f638]
    OS Thread Id: 0x1db4 (3)
    Child SP       IP Call Site
    0465ed4c 77c3c1ac [GCFrame: 0465ed4c]
    0465ee24 77c3c1ac [GCFrame: 0465ee24]
    0465ee40 77c3c1ac [HelperMethodFrame_1OBJ: 0465ee40] System.Threading.Monitor.ReliableEnter(System.Object, Boolean ByRef)
    0465eebc 68c9a703 System.IO.IsolatedStorage.IsolatedStorageFile.Unlock()
    0465eee8 68c96ef7 System.IO.IsolatedStorage.IsolatedStorageFileStream.Write(Byte[], Int32, Int32)
    0465ef34 5e76e1c4 MS.Internal.IO.Packaging.SparseMemoryStream.CopyMemoryBlocksToStream(System.IO.Stream)
    0465ef88 5e76cfd9 MS.Internal.IO.Packaging.SparseMemoryStream.SwitchModeIfNecessary()
    0465efdc 5e76cb8f MS.Internal.IO.Packaging.SparseMemoryStream.Write(Byte[], Int32, Int32)
    0465eff8 5e91522d MS.Internal.IO.Packaging.CompressEmulationStream.Write(Byte[], Int32, Int32)
    0465f014 5e76becb MS.Internal.IO.Packaging.CompressStream.Write(Byte[], Int32, Int32)
    0465f030 5e76bdc8 MS.Internal.IO.Zip.ProgressiveCrcCalculatingStream.Write(Byte[], Int32, Int32)
    0465f058 5e76bd42 MS.Internal.IO.Zip.ZipIOModeEnforcingStream.Write(Byte[], Int32, Int32)
    0465f070 64bb238f System.Xml.XmlUtf8RawTextWriter.FlushBuffer()
    0465f090 64bb219e System.Xml.XmlUtf8RawTextWriter.WriteAttributeTextBlock(Char*, Char*)
    0465f0b0 64bb206c System.Xml.XmlUtf8RawTextWriter.WriteString(System.String)
    0465f0c0 64bb2ac8 System.Xml.XmlWellFormedWriter.WriteString(System.String)
    0465f0e8 04a549aa DocumentFormat.OpenXml.OpenXmlElement.WriteAttributesTo(System.Xml.XmlWriter)
    0465f160 04a5520e DocumentFormat.OpenXml.OpenXmlElement.WriteTo(System.Xml.XmlWriter)
    0465f174 04a550db DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(System.Xml.XmlWriter)
    0465f19c 04a55219 DocumentFormat.OpenXml.OpenXmlElement.WriteTo(System.Xml.XmlWriter)
    0465f1b0 04a550db DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(System.Xml.XmlWriter)
    0465f1d8 04a55219 DocumentFormat.OpenXml.OpenXmlElement.WriteTo(System.Xml.XmlWriter)
    0465f1ec 04a550db DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(System.Xml.XmlWriter)
    0465f214 04a541e3 DocumentFormat.OpenXml.OpenXmlPartRootElement.WriteTo(System.Xml.XmlWriter)
    0465f228 04a53fac DocumentFormat.OpenXml.OpenXmlPartRootElement.SaveToPart(DocumentFormat.OpenXml.Packaging.OpenXmlPart)
    0465f258 04a53ed9 DocumentFormat.OpenXml.OpenXmlPartRootElement.Save()
    0465f264 04a5bfc0 Gridsum.OpenXml.Extension.SpreadsheetExtension.Dump(DocumentFormat.OpenXml.Packaging.WorksheetPart, Int32, Int32, System.Object[,], Boolean, DocumentFormat.OpenXml.Spreadsheet.Cell)
    0465f3cc 04a59901 Gridsum.PowerReport.Core.ExcelTemplateEngine.OutputResultSet(DocumentFormat.OpenXml.Packaging.WorksheetPart, Gridsum.PowerReport.Core.IndexableDataTable, Int32, Int32, Gridsum.PowerReport.Core.DumpToTableCommand, TemplateCells)
    0465f52c 04a58ae7 Gridsum.PowerReport.Core.ExcelTemplateEngine.DumpToTable(Gridsum.PowerReport.Core.ExcelTemplateControl, Gridsum.PowerReport.Core.DumpToTableCommand, Gridsum.PowerReport.Core.IndexableDataTable)
    0465f5e8 04a58417 Gridsum.PowerReport.Core.ExcelTemplateEngine.ProcessDumpCommand(Gridsum.PowerReport.Core.ExcelTemplateControl, Gridsum.PowerReport.Core.DumpCommand, Gridsum.PowerReport.Core.IIndexable)
    0465f644 04a55944 Gridsum.PowerReport.Core.ExcelTemplateEngine.ProcessNonDataSourceControl(Gridsum.PowerReport.Core.TemplateControl)
    0465f694 007f1484 Gridsum.PowerReport.Core.TemplateEngine.ProcessDocument(System.IO.Stream, Gridsum.PowerReport.Core.DataContext)
    0465f750 007f1143 Gridsum.PowerReport.Core.TemplateEngine.ProcessDocument(System.String, System.String, Gridsum.PowerReport.Core.DataContext)
    0465f7d0 007f0425 TestMultipleThread.ReportGenerator.Generate(System.String) [e:CodeDemo公司示例TestMultipleThreadReportGenerator.cs @ 52]
    0465f84c 007f01e5 TestMultipleThread.Program.<Main>b__0(System.Object) [e:CodeDemo公司示例TestMultipleThreadProgram.cs @ 17]
    0465f858 6849e6c8 System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
    0465f864 68483207 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
    0465f8d0 68483156 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
    0465f8e4 68483121 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
    0465f8fc 68439f36 System.Threading.ThreadHelper.ThreadStart(System.Object)
    0465fa50 69202652 [GCFrame: 0465fa50]
    0465fc34 69202652 [DebuggerU2MCatchHandlerFrame: 0465fc34]
    OS Thread Id: 0x19d4 (4)
    Child SP       IP Call Site
    047cebf0 77c3c1ac [GCFrame: 047cebf0]
    047ced94 77c3c1ac [GCFrame: 047ced94]
    047ced44 77c3c1ac [HelperMethodFrame: 047ced44] System.Threading.Monitor.ReliableEnter(System.Object, Boolean ByRef)
    047cedd4 5e8f8bdf MS.Internal.IO.Packaging.PackagingUtilities.CreateUserScopedIsolatedStorageFileStreamWithRandomName(Int32, System.String ByRef)
    047cee10 5e91510e MS.Internal.IO.Packaging.SparseMemoryStream.EnsureIsolatedStoreStream()
    047cee18 5e76cfcf MS.Internal.IO.Packaging.SparseMemoryStream.SwitchModeIfNecessary()
    047cee6c 5e76cb8f MS.Internal.IO.Packaging.SparseMemoryStream.Write(Byte[], Int32, Int32)
    047cee88 5e91522d MS.Internal.IO.Packaging.CompressEmulationStream.Write(Byte[], Int32, Int32)
    047ceea4 5e76becb MS.Internal.IO.Packaging.CompressStream.Write(Byte[], Int32, Int32)
    047ceec0 5e76bdc8 MS.Internal.IO.Zip.ProgressiveCrcCalculatingStream.Write(Byte[], Int32, Int32)
    047ceee8 5e76bd42 MS.Internal.IO.Zip.ZipIOModeEnforcingStream.Write(Byte[], Int32, Int32)
    047cef00 64bb238f System.Xml.XmlUtf8RawTextWriter.FlushBuffer()
    047cef20 64bb219e System.Xml.XmlUtf8RawTextWriter.WriteAttributeTextBlock(Char*, Char*)
    047cef40 64bb206c System.Xml.XmlUtf8RawTextWriter.WriteString(System.String)
    047cef50 64bb2ac8 System.Xml.XmlWellFormedWriter.WriteString(System.String)
    047cef78 04a549aa DocumentFormat.OpenXml.OpenXmlElement.WriteAttributesTo(System.Xml.XmlWriter)
    047ceff0 04a5520e DocumentFormat.OpenXml.OpenXmlElement.WriteTo(System.Xml.XmlWriter)
    047cf004 04a550db DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(System.Xml.XmlWriter)
    047cf02c 04a55219 DocumentFormat.OpenXml.OpenXmlElement.WriteTo(System.Xml.XmlWriter)
    047cf040 04a550db DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(System.Xml.XmlWriter)
    047cf068 04a55219 DocumentFormat.OpenXml.OpenXmlElement.WriteTo(System.Xml.XmlWriter)
    047cf07c 04a550db DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(System.Xml.XmlWriter)
    047cf0a4 04a541e3 DocumentFormat.OpenXml.OpenXmlPartRootElement.WriteTo(System.Xml.XmlWriter)
    047cf0b8 04a53fac DocumentFormat.OpenXml.OpenXmlPartRootElement.SaveToPart(DocumentFormat.OpenXml.Packaging.OpenXmlPart)
    047cf0e8 04a53ed9 DocumentFormat.OpenXml.OpenXmlPartRootElement.Save()
    047cf0f4 04a5bfc0 Gridsum.OpenXml.Extension.SpreadsheetExtension.Dump(DocumentFormat.OpenXml.Packaging.WorksheetPart, Int32, Int32, System.Object[,], Boolean, DocumentFormat.OpenXml.Spreadsheet.Cell)
    047cf25c 04a59901 Gridsum.PowerReport.Core.ExcelTemplateEngine.OutputResultSet(DocumentFormat.OpenXml.Packaging.WorksheetPart, Gridsum.PowerReport.Core.IndexableDataTable, Int32, Int32, Gridsum.PowerReport.Core.DumpToTableCommand, TemplateCells)
    047cf3bc 04a58ae7 Gridsum.PowerReport.Core.ExcelTemplateEngine.DumpToTable(Gridsum.PowerReport.Core.ExcelTemplateControl, Gridsum.PowerReport.Core.DumpToTableCommand, Gridsum.PowerReport.Core.IndexableDataTable)
    047cf478 04a58417 Gridsum.PowerReport.Core.ExcelTemplateEngine.ProcessDumpCommand(Gridsum.PowerReport.Core.ExcelTemplateControl, Gridsum.PowerReport.Core.DumpCommand, Gridsum.PowerReport.Core.IIndexable)
    047cf4d4 04a55944 Gridsum.PowerReport.Core.ExcelTemplateEngine.ProcessNonDataSourceControl(Gridsum.PowerReport.Core.TemplateControl)
    047cf524 007f1484 Gridsum.PowerReport.Core.TemplateEngine.ProcessDocument(System.IO.Stream, Gridsum.PowerReport.Core.DataContext)
    047cf5e0 007f1143 Gridsum.PowerReport.Core.TemplateEngine.ProcessDocument(System.String, System.String, Gridsum.PowerReport.Core.DataContext)
    047cf660 007f0425 TestMultipleThread.ReportGenerator.Generate(System.String) [e:CodeDemo公司示例TestMultipleThreadReportGenerator.cs @ 52]
    047cf6dc 007f01e5 TestMultipleThread.Program.<Main>b__0(System.Object) [e:CodeDemo公司示例TestMultipleThreadProgram.cs @ 17]
    047cf6e8 6849e6c8 System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
    047cf6f4 68483207 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
    047cf760 68483156 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
    047cf774 68483121 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
    047cf78c 68439f36 System.Threading.ThreadHelper.ThreadStart(System.Object)
    047cf8e0 69202652 [GCFrame: 047cf8e0]
    047cfac4 69202652 [DebuggerU2MCatchHandlerFrame: 047cfac4]
    OS Thread Id: 0x1e04 (5)
    Child SP       IP Call Site
    0490eb8c 77c3bc3c [InlinedCallFrame: 0490eb8c]
    0490eb88 68b210b1 DomainNeutralILStubClass.IL_STUB_PInvoke(System.IO.IsolatedStorage.SafeIsolatedStorageFileHandle, Boolean)
    0490eb8c 68c9a618 [InlinedCallFrame: 0490eb8c] System.IO.IsolatedStorage.IsolatedStorageFile.Lock(System.IO.IsolatedStorage.SafeIsolatedStorageFileHandle, Boolean)
    0490ebe0 68c9a618 System.IO.IsolatedStorage.IsolatedStorageFile.Lock(Boolean ByRef)
    0490ec10 68c96776 System.IO.IsolatedStorage.IsolatedStorageFileStream..ctor(System.String, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, Int32, System.IO.IsolatedStorage.IsolatedStorageFile)
    0490ec60 5e8f96bc MS.Internal.IO.Packaging.PackagingUtilities+SafeIsolatedStorageFileStream..ctor(System.String, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, ReliableIsolatedStorageFileFolder)
    0490ec84 5e8f8c10 MS.Internal.IO.Packaging.PackagingUtilities.CreateUserScopedIsolatedStorageFileStreamWithRandomName(Int32, System.String ByRef)
    0490ecc0 5e91510e MS.Internal.IO.Packaging.SparseMemoryStream.EnsureIsolatedStoreStream()
    0490ecc8 5e76cfcf MS.Internal.IO.Packaging.SparseMemoryStream.SwitchModeIfNecessary()
    0490ed1c 5e76cb8f MS.Internal.IO.Packaging.SparseMemoryStream.Write(Byte[], Int32, Int32)
    0490ed38 5e91522d MS.Internal.IO.Packaging.CompressEmulationStream.Write(Byte[], Int32, Int32)
    0490ed54 5e76becb MS.Internal.IO.Packaging.CompressStream.Write(Byte[], Int32, Int32)
    0490ed70 5e76bdc8 MS.Internal.IO.Zip.ProgressiveCrcCalculatingStream.Write(Byte[], Int32, Int32)
    0490ed98 5e76bd42 MS.Internal.IO.Zip.ZipIOModeEnforcingStream.Write(Byte[], Int32, Int32)
    0490edb0 64bb238f System.Xml.XmlUtf8RawTextWriter.FlushBuffer()
    0490edd0 64bb219e System.Xml.XmlUtf8RawTextWriter.WriteAttributeTextBlock(Char*, Char*)
    0490edf0 64bb206c System.Xml.XmlUtf8RawTextWriter.WriteString(System.String)
    0490ee00 64bb2ac8 System.Xml.XmlWellFormedWriter.WriteString(System.String)
    0490ee28 04a549aa DocumentFormat.OpenXml.OpenXmlElement.WriteAttributesTo(System.Xml.XmlWriter)
    0490eea0 04a5520e DocumentFormat.OpenXml.OpenXmlElement.WriteTo(System.Xml.XmlWriter)
    0490eeb4 04a550db DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(System.Xml.XmlWriter)
    0490eedc 04a55219 DocumentFormat.OpenXml.OpenXmlElement.WriteTo(System.Xml.XmlWriter)
    0490eef0 04a550db DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(System.Xml.XmlWriter)
    0490ef18 04a55219 DocumentFormat.OpenXml.OpenXmlElement.WriteTo(System.Xml.XmlWriter)
    0490ef2c 04a550db DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(System.Xml.XmlWriter)
    0490ef54 04a541e3 DocumentFormat.OpenXml.OpenXmlPartRootElement.WriteTo(System.Xml.XmlWriter)
    0490ef68 04a53fac DocumentFormat.OpenXml.OpenXmlPartRootElement.SaveToPart(DocumentFormat.OpenXml.Packaging.OpenXmlPart)
    0490ef98 04a53ed9 DocumentFormat.OpenXml.OpenXmlPartRootElement.Save()
    0490efa4 04a5bfc0 Gridsum.OpenXml.Extension.SpreadsheetExtension.Dump(DocumentFormat.OpenXml.Packaging.WorksheetPart, Int32, Int32, System.Object[,], Boolean, DocumentFormat.OpenXml.Spreadsheet.Cell)
    0490f10c 04a59901 Gridsum.PowerReport.Core.ExcelTemplateEngine.OutputResultSet(DocumentFormat.OpenXml.Packaging.WorksheetPart, Gridsum.PowerReport.Core.IndexableDataTable, Int32, Int32, Gridsum.PowerReport.Core.DumpToTableCommand, TemplateCells)
    0490f26c 04a58ae7 Gridsum.PowerReport.Core.ExcelTemplateEngine.DumpToTable(Gridsum.PowerReport.Core.ExcelTemplateControl, Gridsum.PowerReport.Core.DumpToTableCommand, Gridsum.PowerReport.Core.IndexableDataTable)
    0490f328 04a58417 Gridsum.PowerReport.Core.ExcelTemplateEngine.ProcessDumpCommand(Gridsum.PowerReport.Core.ExcelTemplateControl, Gridsum.PowerReport.Core.DumpCommand, Gridsum.PowerReport.Core.IIndexable)
    0490f384 04a55944 Gridsum.PowerReport.Core.ExcelTemplateEngine.ProcessNonDataSourceControl(Gridsum.PowerReport.Core.TemplateControl)
    0490f3d4 007f1484 Gridsum.PowerReport.Core.TemplateEngine.ProcessDocument(System.IO.Stream, Gridsum.PowerReport.Core.DataContext)
    0490f490 007f1143 Gridsum.PowerReport.Core.TemplateEngine.ProcessDocument(System.String, System.String, Gridsum.PowerReport.Core.DataContext)
    0490f510 007f0425 TestMultipleThread.ReportGenerator.Generate(System.String) [e:CodeDemo公司示例TestMultipleThreadReportGenerator.cs @ 52]
    0490f58c 007f01e5 TestMultipleThread.Program.<Main>b__0(System.Object) [e:CodeDemo公司示例TestMultipleThreadProgram.cs @ 17]
    0490f598 6849e6c8 System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
    0490f5a4 68483207 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
    0490f610 68483156 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
    0490f624 68483121 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
    0490f63c 68439f36 System.Threading.ThreadHelper.ThreadStart(System.Object)
    0490f790 69202652 [GCFrame: 0490f790]
    0490f974 69202652 [DebuggerU2MCatchHandlerFrame: 0490f974]
    OS Thread Id: 0×1370 (6)
    Unable to walk the managed stack. The current thread is likely not a
    managed thread. You can run !threads to get a list of managed threads in
    the process
    Failed to start stack walk: 80070057
    OS Thread Id: 0x219c (7)
    Unable to walk the managed stack. The current thread is likely not a
    managed thread. You can run !threads to get a list of managed threads in
    the process
    Failed to start stack walk: 80070057

    可以看到, 线程3, 4, 都进入了Threading.Monitor.ReliableEnter的等待状态. 线程5进入的是IsolatedStorageFile.Lock. 具体的代码调用参看这里http://referencesource.microsoft.com/#mscorlib/system/io/isolatedstorage/isolatedstoragefile.cs#45da6d4fc07becbc

    直接调用了com的东西, (此外,多说一句.net本身就是个com)

    2. 那么接下来我们看看线程3, 4要获取的锁被那个阻塞了吧. 首先运行命令~3e!clrstack –a 检查线程3的堆栈参数以及变量情况

    0:005> ~3e!clrstack -a
    OS Thread Id: 0x1db4 (3)
    Child SP       IP Call Site
    0465ed4c 77c3c1ac [GCFrame: 0465ed4c]
    0465ee24 77c3c1ac [GCFrame: 0465ee24]
    0465ee40 77c3c1ac [HelperMethodFrame_1OBJ: 0465ee40] System.Threading.Monitor.ReliableEnter(System.Object, Boolean ByRef)
    0465eebc 68c9a703 System.IO.IsolatedStorage.IsolatedStorageFile.Unlock()
    PARAMETERS:
    this (<CLR reg>) = 0x0d01aa6c
    LOCALS:
    0x0465eec0 = 0×00000000
    0x0465eebc = 0x0d01aabc

    0465eee8 68c96ef7 System.IO.IsolatedStorage.IsolatedStorageFileStream.Write(Byte[], Int32, Int32)
    PARAMETERS:
    this (0x0465eeec) = 0x0d0fc954
    buffer = <no data>
    offset = <no data>
    count = <no data>
    LOCALS:
    0x0465ef00 = 0×00000001
    <no data>
    <no data>

    0465ef34 5e76e1c4 MS.Internal.IO.Packaging.SparseMemoryStream.CopyMemoryBlocksToStream(System.IO.Stream)
    PARAMETERS:
    this (0x0465ef38) = 0x02e0e550
    targetStream (0x0465ef34) = 0x0d0fc954
    LOCALS:
    0x0465ef5c = 0×00000000
    <CLR reg> = 0x0af4e5b4
    <no data>

    省略部分堆栈内容, 要不太长了. ….

    3. 检查一下变量0x0d01aabc 是什么东东. 运行!do 0x0d01aabc 命令查看对象信息.

    0:005> !do 0x0d01aabc
    Name:        System.Object
    MethodTable: 685726a4
    EEClass:     68163f70
    Size:        12(0xc) bytes
    File:        C:WINDOWSMicrosoft.NetassemblyGAC_32mscorlibv4.0_4.0.0.0__b77a5c561934e089mscorlib.dll
    Object
    Fields:
    None

    不出所料, 就是个object对象.

    4. 检查对象头信息, 运行命令dd 0x0d01aabc-4 l1  这里的”-4”操作是为了定位到对象头.

    0:005> dd 0x0d01aabc-4 l1
    0d01aab8  0800000e

    5. 这个对象是被那个线程持有着呢, 运行命令!syncblk 0xe 检查索引块中的index为0xe的索引块信息.

    0:005> !syncblk 0xe
    Index         SyncBlock MonitorHeld Recursion Owning Thread Info          SyncBlock Owner
    14 008f7ad8            3         1 008fc420 1e04   5   0d01aabc System.Object
    —————————–
    Total           14
    CCW             0
    RCW             0
    ComClassFactory 0
    Free            0

    可以看到,当前的锁是被线程5持有着.

    6. 按照以上操作重现检查线程4, 同样发现所等待的锁也是被线程5持有着.

    线程5持有两个锁, 分别阻塞了线程3, 4. 线程5在干嘛呢.

    7. 检查线程5的堆栈情况, 使用~5e!dumpstack 命令打印混合堆栈信息.

    0:005> ~5e!dumpstack
    OS Thread Id: 0x1e04 (5)
    Current frame: ntdll!NtWaitForSingleObject+0xc
    ChildEBP RetAddr  Caller, Callee
    0490eaa4 77901180 KERNELBASE!WaitForSingleObjectEx+0×99, calling ntdll!NtWaitForSingleObject
    0490eb14 779010c0 KERNELBASE!WaitForSingleObject+0×12, calling KERNELBASE!WaitForSingleObjectEx
    0490eb28 6960d595 clr!AccountingInfo::AcquireLock+0×17, calling KERNELBASE!WaitForSingleObject
    0490eb3c 6960d980 clr!COMIsolatedStorageFile::Lock+0×55, calling clr!AccountingInfo::AcquireLock
    0490eb78 68b210b1 (MethodDesc 682e86c0 +0×65 DomainNeutralILStubClass.IL_STUB_PInvoke(System.IO.IsolatedStorage.SafeIsolatedStorageFileHandle, Boolean))
    0490eb98 68b210b1 (MethodDesc 682e86c0 +0×65 DomainNeutralILStubClass.IL_STUB_PInvoke(System.IO.IsolatedStorage.SafeIsolatedStorageFileHandle, Boolean))
    0490ebc0 68452fd2 (MethodDesc 681fdd10 +0xb2 System.Text.StringBuilder.ToString()), calling (MethodDesc 681f8d54 +0 System.Buffer.Memcpy(Byte*, Byte*, Int32))
    0490ebd8 68c9a618 (MethodDesc 682a418c +0xa4 System.IO.IsolatedStorage.IsolatedStorageFile.Lock(Boolean ByRef)), calling 6841bbc4
    0490ec08 68c96776 (MethodDesc 682cd784 +0x13e System.IO.IsolatedStorage.IsolatedStorageFileStream..ctor(System.String, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, Int32, System.IO.IsolatedStorage.IsolatedStorageFile)), calling 683ef810
    0490ec44 5e8f96bc (MethodDesc 5e6ed164 +0x3c MS.Internal.IO.Packaging.PackagingUtilities+SafeIsolatedStorageFileStream..ctor(System.String, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, ReliableIsolatedStorageFileFolder)), calling 68422674
    0490ec6c 5e8f8c10 (MethodDesc 5e6db0d8 +0xac MS.Internal.IO.Packaging.PackagingUtilities.CreateUserScopedIsolatedStorageFileStreamWithRandomName(Int32, System.String ByRef)), calling 5e735a6c
    0490ecb8 5e91510e (MethodDesc 5e6dca84 +0×16 MS.Internal.IO.Packaging.SparseMemoryStream.EnsureIsolatedStoreStream()), calling (MethodDesc 5e6db0d8 +0 MS.Internal.IO.Packaging.PackagingUtilities.CreateUserScopedIsolatedStorageFileStreamWithRandomName(Int32, System.String ByRef))
    0490ecc0 5e76cfcf (MethodDesc 5e6dca6c +0x4b MS.Internal.IO.Packaging.SparseMemoryStream.SwitchModeIfNecessary()), calling (MethodDesc 5e6dca84 +0 MS.Internal.IO.Packaging.SparseMemoryStream.EnsureIsolatedStoreStream())
    0490ed14 5e76cb8f (MethodDesc 5e6dc9f4 +0x6b MS.Internal.IO.Packaging.SparseMemoryStream.Write(Byte[], Int32, Int32)), calling (MethodDesc 5e6dca6c +0 MS.Internal.IO.Packaging.SparseMemoryStream.SwitchModeIfNecessary())
    0490ed28 5e91522d (MethodDesc 5e6dcbe8 +0x3d MS.Internal.IO.Packaging.CompressEmulationStream.Write(Byte[], Int32, Int32))
    0490ed44 5e76becb (MethodDesc 5e6dbc20 +0x4b MS.Internal.IO.Packaging.CompressStream.Write(Byte[], Int32, Int32))
    0490ed60 5e76bdc8 (MethodDesc 5e6dbd34 +0×60 MS.Internal.IO.Zip.ProgressiveCrcCalculatingStream.Write(Byte[], Int32, Int32))
    0490ed70 5e767503 (MethodDesc 5e6dbd24 +0×23 MS.Internal.IO.Zip.ProgressiveCrcCalculatingStream.Seek(Int64, System.IO.SeekOrigin))
    0490ed88 5e76bd42 (MethodDesc 5e6dbed4 +0×56 MS.Internal.IO.Zip.ZipIOModeEnforcingStream.Write(Byte[], Int32, Int32))
    0490eda0 64bb238f (MethodDesc 64b228c4 +0x2f System.Xml.XmlUtf8RawTextWriter.FlushBuffer())
    0490edc8 64bb219e (MethodDesc 64b228cc +0x11e System.Xml.XmlUtf8RawTextWriter.WriteAttributeTextBlock(Char*, Char*))
    0490ede4 64bb206c (MethodDesc 64b22884 +0x2c System.Xml.XmlUtf8RawTextWriter.WriteString(System.String)), calling (MethodDesc 64b228cc +0 System.Xml.XmlUtf8RawTextWriter.WriteAttributeTextBlock(Char*, Char*))
    0490edf8 64bb2ac8 (MethodDesc 64b0975c +0×38 System.Xml.XmlWellFormedWriter.WriteString(System.String))
    0490ee20 04a549aa (MethodDesc 0088f040 +0×252 DocumentFormat.OpenXml.OpenXmlElement.WriteAttributesTo(System.Xml.XmlWriter))
    0490ee98 04a5520e (MethodDesc 0088ef04 +0xde DocumentFormat.OpenXml.OpenXmlElement.WriteTo(System.Xml.XmlWriter))
    0490eeac 04a550db (MethodDesc 0088f558 +0×63 DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(System.Xml.XmlWriter))
    0490eed4 04a55219 (MethodDesc 0088ef04 +0xe9 DocumentFormat.OpenXml.OpenXmlElement.WriteTo(System.Xml.XmlWriter))
    0490eee8 04a550db (MethodDesc 0088f558 +0×63 DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(System.Xml.XmlWriter))
    0490ef10 04a55219 (MethodDesc 0088ef04 +0xe9 DocumentFormat.OpenXml.OpenXmlElement.WriteTo(System.Xml.XmlWriter))
    0490ef24 04a550db (MethodDesc 0088f558 +0×63 DocumentFormat.OpenXml.OpenXmlCompositeElement.WriteContentTo(System.Xml.XmlWriter))
    0490ef3c 007fbb8a (MethodDesc 0088f4a4 +0xa DocumentFormat.OpenXml.OpenXmlCompositeElement.get_LastChild()), calling (MethodDesc 0088f0ac +0 DocumentFormat.OpenXml.OpenXmlElement.MakeSureParsed())
    0490ef4c 04a541e3 (MethodDesc 0088f800 +0x12b DocumentFormat.OpenXml.OpenXmlPartRootElement.WriteTo(System.Xml.XmlWriter))
    0490ef60 04a53fac (MethodDesc 0088f7b8 +0×94 DocumentFormat.OpenXml.OpenXmlPartRootElement.SaveToPart(DocumentFormat.OpenXml.Packaging.OpenXmlPart))
    0490ef90 04a53ed9 (MethodDesc 0088f7e8 +0×11 DocumentFormat.OpenXml.OpenXmlPartRootElement.Save()), calling (MethodDesc 0088f7b8 +0 DocumentFormat.OpenXml.OpenXmlPartRootElement.SaveToPart(DocumentFormat.OpenXml.Packaging.OpenXmlPart))
    0490ef9c 04a5bfc0 (MethodDesc 049dd138 +0x9f8 Gridsum.OpenXml.Extension.SpreadsheetExtension.Dump(DocumentFormat.OpenXml.Packaging.WorksheetPart, Int32, Int32, System.Object[,], Boolean, DocumentFormat.OpenXml.Spreadsheet.Cell)), calling (MethodDesc 0088f7e8 +0 DocumentFormat.OpenXml.OpenXmlPartRootElement.Save())
    0490f0f4 04a59901 (MethodDesc 005e46b4 +0×661 Gridsum.PowerReport.Core.ExcelTemplateEngine.OutputResultSet(DocumentFormat.OpenXml.Packaging.WorksheetPart, Gridsum.PowerReport.Core.IndexableDataTable, Int32, Int32, Gridsum.PowerReport.Core.DumpToTableCommand, TemplateCells)), calling (MethodDesc 049dd138 +0 Gridsum.OpenXml.Extension.SpreadsheetExtension.Dump(DocumentFormat.OpenXml.Packaging.WorksheetPart, Int32, Int32, System.Object[,], Boolean, DocumentFormat.OpenXml.Spreadsheet.Cell))
    0490f254 04a58ae7 (MethodDesc 005e46c8 +0x2df Gridsum.PowerReport.Core.ExcelTemplateEngine.DumpToTable(Gridsum.PowerReport.Core.ExcelTemplateControl, Gridsum.PowerReport.Core.DumpToTableCommand, Gridsum.PowerReport.Core.IndexableDataTable)), calling (MethodDesc 005e46b4 +0 Gridsum.PowerReport.Core.ExcelTemplateEngine.OutputResultSet(DocumentFormat.OpenXml.Packaging.WorksheetPart, Gridsum.PowerReport.Core.IndexableDataTable, Int32, Int32, Gridsum.PowerReport.Core.DumpToTableCommand, TemplateCells))
    0490f318 04a58417 (MethodDesc 005e46d8 +0x1c7 Gridsum.PowerReport.Core.ExcelTemplateEngine.ProcessDumpCommand(Gridsum.PowerReport.Core.ExcelTemplateControl, Gridsum.PowerReport.Core.DumpCommand, Gridsum.PowerReport.Core.IIndexable))
    0490f374 04a55944 (MethodDesc 005e4708 +0×124 Gridsum.PowerReport.Core.ExcelTemplateEngine.ProcessNonDataSourceControl(Gridsum.PowerReport.Core.TemplateControl))
    0490f3cc 007f1484 (MethodDesc 005e4268 +0x2e4 Gridsum.PowerReport.Core.TemplateEngine.ProcessDocument(System.IO.Stream, Gridsum.PowerReport.Core.DataContext))
    0490f484 007f1143 (MethodDesc 005e4278 +0×223 Gridsum.PowerReport.Core.TemplateEngine.ProcessDocument(System.String, System.String, Gridsum.PowerReport.Core.DataContext))
    0490f500 007f0425 (MethodDesc 005e3858 +0×225 TestMultipleThread.ReportGenerator.Generate(System.String)), calling (MethodDesc 005e4278 +0 Gridsum.PowerReport.Core.TemplateEngine.ProcessDocument(System.String, System.String, Gridsum.PowerReport.Core.DataContext))
    0490f584 007f01e5 (MethodDesc 005e37f8 +0×45 TestMultipleThread.Program.<Main>b__0(System.Object)), calling (MethodDesc 005e3858 +0 TestMultipleThread.ReportGenerator.Generate(System.String))
    0490f590 6849e6c8 (MethodDesc 682987e8 +0x9c System.Threading.ThreadHelper.ThreadStart_Context(System.Object))
    0490f59c 68483207 (MethodDesc 68202364 +0xa7 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean))
    0490f600 68483156 (MethodDesc 68202358 +0×16 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)), calling (MethodDesc 68202364 +0 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean))
    0490f614 68483121 (MethodDesc 6820234c +0×41 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)), calling (MethodDesc 68202358 +0 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean))
    0490f630 68439f36 (MethodDesc 681e1854 +0x4e System.Threading.ThreadHelper.ThreadStart(System.Object)), calling (MethodDesc 6820234c +0 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object))
    0490f648 69202652 clr!CallDescrWorkerInternal+0×34
    0490f654 692111c0 clr!CallDescrWorkerWithHandler+0x6b, calling clr!CallDescrWorkerInternal
    0490f668 69211179 clr!CallDescrWorkerWithHandler+0×20, calling clr!_alloca_probe
    0490f6a8 6921e2d4 clr!MethodDescCallSite::CallTargetWorker+0×152, calling clr!CallDescrWorkerWithHandler
    0490f6cc 6921b213 clr!ArgIteratorTemplate<ArgIteratorBase>::ComputeReturnFlags+0×11, calling clr!MetaSig::GetReturnTypeNormalized
    0490f6d4 6922050a clr!MetaSig::SkipArg+0×25, calling clr!SigParser::SkipExactlyOne
    0490f6dc 6921e22c clr!MethodDescCallSite::CallTargetWorker+0x6c, calling clr!_alloca_probe_16
    0490f708 6921e33a clr!MethodDescCallSite::MethodDescCallSite+0x4a, calling clr!ArgIteratorTemplate<ArgIteratorBase>::ForceSigWalk
    0490f728 692f174d clr!ThreadNative::KickOffThread_Worker+0×173, calling clr!MethodDescCallSite::CallTargetWorker
    0490f848 77712901 combase!IsRunningInRPCSS+0×33, calling combase!__security_check_cookie
    0490f850 77c3e9b1 ntdll!RtlAllocateHeap+0xc6, calling ntdll!RtlpLowFragHeapAllocFromContext
    0490f868 77712972 combase!RegisterThreadCleanupCallback+0×25, calling KERNELBASE!FlsSetValue
    0490f89c 69294b5d clr!ManagedThreadBase_DispatchInner+0×67
    0490f8b4 69294bcb clr!ManagedThreadBase_DispatchMiddle+0×82, calling clr!ManagedThreadBase_DispatchInner
    0490f8dc 69202df7 clr!EEHeapAlloc+0x2c, calling ntdll!RtlAllocateHeap
    0490f8e4 69201e1d clr!CrstBase::Enter+0x15a, calling ntdll!RtlTryEnterCriticalSection
    0490f8f8 6920c318 clr!ClrFlsIncrementValue+0×9, calling clr!ClrFlsGetBlock
    0490f90c 6920d690 clr!ThreadStore::UnlockThreadStore+0x3f, calling clr!ClrFlsIncrementValue
    0490f918 6939a166 clr!ThreadStore::TransferStartedThread+0xfd, calling clr!_EH_epilog3
    0490f958 69294c98 clr!ManagedThreadBase_DispatchOuter+0x5b, calling clr!ManagedThreadBase_DispatchMiddle
    0490f9b4 69398621 clr!ManagedThreadBase_FullTransitionWithAD+0x2f, calling clr!ManagedThreadBase_DispatchOuter
    0490f9d8 692f1609 clr!ThreadNative::KickOffThread+0x1d1, calling clr!ManagedThreadBase_FullTransitionWithAD
    0490fa20 69210bf8 clr!EEHeapFree+0×31, calling KERNEL32!HeapFreeStub
    0490fa38 69210c1d clr!EEHeapFreeInProcessHeap+0x2f, calling clr!EEHeapFree
    0490fa54 69398af9 clr!Thread::intermediateThreadProc+0x4d
    0490fc58 69398ae7 clr!Thread::intermediateThreadProc+0x3b, calling clr!_alloca_probe_16
    0490fc6c 775c495d KERNEL32!BaseThreadInitThunk+0xe
    0490fc78 77c498ee ntdll!__RtlUserThreadStart+0×20
    0490fcbc 77c498c4 ntdll!_RtlUserThreadStart+0x1b, calling ntdll!__RtlUserThreadStart

    看一看到, 最终调用了AccountingInfo::AcquireLock函数. 这个函数是可以在ssclr中查看具体请参看https://github.com/gbarnett/shared-source-cli-2.0/blob/master/clr/src/vm/comisolatedstorage.cpp

    我们可以看到有如下代码

    HRESULT AccountingInfo::Init()
    {
        CONTRACTL {
            THROWS;
            GC_TRIGGERS;
            MODE_ANY;
            PRECONDITION(m_hLock == NULL); // Init was called multiple times on this object without calling Close
            SO_TOLERANT;
        } CONTRACTL_END;
    
        // Create the synchronization object
    
        HRESULT hr = S_OK;
        BEGIN_SO_INTOLERANT_CODE(GetThread())
        m_hLock = WszCreateMutex(NULL, FALSE /* Initially not owned */, m_wszName);
    //省略.....
    }
    
    HRESULT AccountingInfo::Lock()
    {
        CONTRACTL {
            THROWS;
            GC_TRIGGERS;
            MODE_ANY;
        } CONTRACTL_END;
    
        // Lock is intented to be used for inter process/thread synchronization.
    
    #ifdef _DEBUG
        _ASSERTE(m_hLock);
    
        LOG((LF_STORE, LL_INFO10000, "Lock %S, thread 0x%x start..
    ",
                m_wszName, GetCurrentThreadId()));
    #endif
    
        DWORD dwRet;
        {
            GCX_PREEMP();
            // m_hLock is a mutex
            Thread::BeginThreadAffinity();
            dwRet = WaitForSingleObject(m_hLock, INFINITE);
        }
    //省略.....
    }

    查看变量m_hLock可知, 它是个互斥体.

    8. 查看互斥体的情况, 通过命令!handle来获取当前进程所有的句柄

    0:005> !handle
    Handle 20
    Type             ALPC Port
    Handle 24
    Type             File
    Handle 28
    Type             File
    Handle 2c
    Type             File
    Handle 30
    Type             Key
    Handle 34
    Type             Mutant
    Handle 38
    Type             Event
    Handle 5c
    Type             Semaphore
    Handle 60
    Type             File
    Handle 64
    Type             Semaphore
    Handle 68
    Type             Key
    Handle 6c
    Type             Mutant
    Handle d4
    Type             Event
    Handle d8
    Type             Mutant
    Handle dc
    Type             Event
    Handle e0
    Type             Mutant
    Handle fc
    Type             Key
    Handle 124
    Type             Directory
    Handle 128
    Type             Mutant
    Handle 130
    Type             Section
    Handle 134
    Type             Section
    Handle 164
    Type             Mutant

    Handle 288
    Type             Section
    Handle 28c
    Type             File
    Handle 294
    Type             Section

    Handle 300
    Type             File
    Handle 308
    Type             File
    Handle 310
    Type             Section
    Handle 330
    Type             Mutant
    Handle 338
    Type             Mutant
    Handle 530
    Type             File
    Handle 540
    Type             ALPC Port
    Handle 548
    Type             ALPC Port
    Handle 560
    Type             WaitCompletionPacket
    Handle 570
    Type             WaitCompletionPacket
    Handle 5f8
    Type             File
    Handle 5fc
    Type             Directory
    Handle 600
    Type             ALPC Port
    Handle 604
    Type             Section
    Handle 608
    Type             Semaphore
    Handle 60c
    Type             Mutant
    Handle 610
    Type             Mutant
    Handle 614
    Type             Semaphore
    Handle 63c
    Type             Section
    Handle 644
    Type             Mutant
    Handle 658
    Type             Section
    Handle 65c
    Type             Section
    Handle 660
    Type             File
    Handle 664
    Type             Section
    Handle 668
    Type             Section
    Handle 66c
    Type             File
    325 Handles
    Type               Count
    None               6
    Event              144
    Section            12
    File               25
    Directory          6
    Mutant             11
    WindowStation      2
    Semaphore          14
    Key                54
    Thread             8
    Desktop            1
    IoCompletion       3
    TpWorkerFactory    3
    ALPC Port          4
    WaitCompletionPacket    32

    //剪了里面的大部分内容.

    可以看到Mutant部分就11.  我们挨个检查一下他们的情况.

    9. 使用!handle 644 f ; !handle 610 ;……….检查句柄的情况.

    Handle 644
    Type             Mutant
    Attributes       0
    GrantedAccess    0x1f0001:
    Delete,ReadControl,WriteDac,WriteOwner,Synch
    QueryState
    HandleCount      2
    PointerCount     65529
    Name             BaseNamedObjectsyiz03mi0er210ttjr55djqhnp3a4bfln
    Object Specific Information
    Mutex is Owned
    Mutant Owner 10e0.1db4
    Handle 610
    Type             Mutant
    Attributes       0
    GrantedAccess    0x1f0001:
    Delete,ReadControl,WriteDac,WriteOwner,Synch
    QueryState
    HandleCount      37
    PointerCount     32805
    Name             Sessions1BaseNamedObjectsonesLockedCacheCounterMutex
    Object Specific Information
    Mutex is Free

    //……省略.

    发现所有的互斥体仅有644是被持有的. 并且可以看到持有的线程是10e0.1db4

    10. 接下来看一下这个线程对应到.NET上是哪个线程. 运行命令!thread可以看到

    0:005> !threads
    ThreadCount:      5
    UnstartedThread:  0
    BackgroundThread: 2
    PendingThread:    0
    DeadThread:       0
    Hosted Runtime:   no
    Lock
    ID OSID ThreadOBJ    State GC Mode     GC Alloc Context  Domain   Count Apt Exception
    0    1 2770 008c3108   203a220 Preemptive  00000000:00000000 008bceb8 0     MTA
    2    2 2020 008cf118     2b220 Preemptive  00000000:00000000 008bceb8 0     MTA (Finalizer)
    3    3 1db4 008f7020   202b020 Preemptive  0D32446C:00000000 008bceb8 0     MTA
    4    4 19d4 008fb198   202b020 Preemptive  0D32295C:00000000 008bceb8 0     MTA
    5    5 1e04 008fc420     2b020 Preemptive  0D325C6C:00000000 008bceb8 2     MTA

    线程3持有了这个互斥体.

    总结以上推到, 线程5持有了两个锁, 并等待某一互斥体. 此互斥体又被线程3持有着, 此时的线程3在期望获取线程5中的锁. 所以产生了死锁.

    这个死锁的特殊之处在于它既非是.NET自身的锁导致的. 也非完全是非托管堆导致的.

    独立存储本身微软已经声明是非线程安全的. 尽管底层对文件访问使用了锁. 但是并发还是会产生死锁等现象(其实也就是因为使用了锁) . 所以写代码的时候需要注意到并发的类库是否是线程安全的, 如果不安全那么一定记得在使用层面上加锁防止底层死锁等问题.

    ps:细心的朋友应该能发现以上逻辑有推到不严密的地方就是, 如何断定线程3的互斥体就是线程5要等待的那个呢? 这个的确在用户态是无法获取得到的. 这个需要内核态调试. 我在本机尝试Dump内核相对比较麻烦也就没有这么去做, 而是遍历了所有互斥体,看出当前进程中只有一个互斥体是有效的且被线程3持有着. 如果线程5在等待一个无效的互斥体按照代码逻辑来说应该是会抛异常的. 所以反过来考虑应该就是在等待线程3所持有的互斥体.

  • 相关阅读:
    redis实现分布式缓存
    redis持久化
    Redis五种数据类型
    Azure Digital Twins(1)-创建实例并设置角色
    Azure Digital Twins(2)- 在本地使用ADT Explorer 管理数字孪生
    Azure Digital Twins(3)- 数字孪生体和数字孪生图
    Azure + 5G + AI + IOT可以这么玩
    使用Azure Storage API 上传 文件解决微信小程序中上传图片的问题
    Azure入门(1)- Azure核心概念
    利用 Management Group 和Policy 控制Azure 指定资源的创建
  • 原文地址:https://www.cnblogs.com/cuiweifu/p/3786461.html
Copyright © 2011-2022 走看看