代码改变世界

并发之阿喀琉斯之踵

2014-04-25 07:58  Franz  阅读(1614)  评论(0编辑  收藏  举报

这两天线上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:\Soft\CodeTools\Debugtools\sosex_32\sosex.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\公司示例\TestMultipleThread\ReportGenerator.cs @ 52]
0465f84c 007f01e5 TestMultipleThread.Program.<Main>b__0(System.Object) [e:\CodeDemo\公司示例\TestMultipleThread\Program.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\公司示例\TestMultipleThread\ReportGenerator.cs @ 52]
047cf6dc 007f01e5 TestMultipleThread.Program.<Main>b__0(System.Object) [e:\CodeDemo\公司示例\TestMultipleThread\Program.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\公司示例\TestMultipleThread\ReportGenerator.cs @ 52]
0490f58c 007f01e5 TestMultipleThread.Program.<Main>b__0(System.Object) [e:\CodeDemo\公司示例\TestMultipleThread\Program.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:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.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..\n",
            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             \BaseNamedObjects\yiz03mi0er210ttjr55djqhnp3a4bfln
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             \Sessions\1\BaseNamedObjects\ZonesLockedCacheCounterMutex
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所持有的互斥体.