C#Web服务卡在等待锁定,不返回

时间:2010-06-15 18:46:29

标签: c# web-services .net-2.0 asmx locking

我们有一个C#(2.0)应用程序,通过Web服务与我们的服务器(在java中)进行通信。

最近我们开始在(仅)我们的一台实验室机器(XP)中看到以下行为: 偶尔(每隔几天),其中一个webservice请求就会卡住,不会返回或超时。

以下是堆栈跟踪,它似乎卡住了。

不知道这里发生了什么。 任何指针都会有很大的帮助。

ESP EIP
05eceeec 7c90eb94 [GCFrame:05eceeec] 05ecefbc 7c90eb94 [HelperMethodFrame_1OBJ:05ecefbc] System.Threading.Monitor.Enter(System.Object的) 05ecf014 7a5b0034 System.Net.ConnectionGroup.Disassociate(System.Net.Connection) 05ecf040 7a5aeaa7 System.Net.Connection.PrepareCloseConnectionSocket(System.Net.ConnectionReturnResult 为ByRef) 05ecf0a4 7a5ac0e1 System.Net.Connection.ReadStartNextRequest(System.Net.WebRequest, System.Net.ConnectionReturnResult ByRef) 05ecf0e8 7a5b1119 System.Net.ConnectStream.CallDone(System.Net.ConnectionReturnResult) 05ecf0fc 7a5b3b5a System.Net.ConnectStream.ReadChunkedSync(Byte [],Int32, INT32) 05ecf114 7a5b2b90 System.Net.ConnectStream.ReadWithoutValidation(Byte [],Int32, Int32,布尔值) 05ecf160 7a5b29cc System.Net.ConnectStream.Read(Byte [],Int32,Int32) 05ecf1a0 79473cab System.IO.StreamReader.ReadBuffer(Char [],Int32,Int32, 布尔ByRef) 05ecf1c4 79473bd6 System.IO.StreamReader.Read(Char [],Int32,Int32) 05ecf1e8 69c29119 System.Xml.XmlTextReaderImpl.ReadData() 05ecf1f8 69c2ad70 System.Xml.XmlTextReaderImpl.ParseDocumentContent() 05ecf20c 69c292d7 System.Xml.XmlTextReaderImpl.Read() 05ecf21c 69c2929d System.Xml.XmlTextReader.Read() 05ecf220 6991b3e7 System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(System.Web.Services.Protocols.SoapClientMessage, System.Net.WebResponse,System.IO.Stream,Boolean) 05ecf268 69919ed1 System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(System.String, System.Object的[])

修改

在David的回答之后,我又看到了所有的线程,并找到了死锁的帮凶:

ESP EIP
11a2f6f0 7c90eb94 [GCFrame:11a2f6f0] 11a2f7c0 7c90eb94 [HelperMethodFrame_1OBJ:11a2f7c0] System.Threading.Monitor.Enter(System.Object) 11a2f818 7a5ae107 System.Net.Connection.CloseOnIdle() 11a2f844 7a5b0403 System.Net.ConnectionGroup.DisableKeepAliveOnConnections() 11a2f878 7a58c035 System.Net.ServicePoint.ReleaseAllConnectionGroups() 11a2f8b4 7a58d40a System.Net.ServicePointManager.IdleServicePointTimeoutCallback(Timer,Int32,System.Object) 11a2f8e8 7a5d2f40 System.Net.TimerThread + TimerNode.Fire() 11a2f928 7a5d2bb2 System.Net.TimerThread + TimerQueue.Fire(Int32 ByRef) 11a2f968 7a5d2540 System.Net.TimerThread.ThreadProc() 11a2f9b4 793d7a7b System.Threading.ThreadHelper.ThreadStart_Context(System.Object) 11a2f9bc 793683dd System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,System.Threading.ContextCallback,System.Object) 11a2f9d4 793d7b5c System.Threading.ThreadHelper.ThreadStart() 11a2fbf8 79e88f63 [GCFrame:11a2fbf8]

那么,我们知道它是否在4.0中修复了吗?

2 个答案:

答案 0 :(得分:1)

这看起来与CLR中的相关...错误? Microsoft Connect

编辑:4.0框架中的代码看起来像锁完全不同。它可能已经修复了这个错误。

答案 1 :(得分:1)

你几乎肯定会遇到僵局。假设您有线程A取出对象2上的锁,然后等待对象1解锁。线程A必须等待,因为线程B在解锁对象2之前已取出对象1上的锁。现在线程A和线程B将永远等待,因为每个线程都在等待另一个解锁某些东西。

使用调试器查看程序中的每个线程,看看哪两个线程都在那里等待锁定。然后找出他们正在等待的锁。然后弄清楚如何重写程序,以便这两个锁永远不会以两个线程上不一致的顺序被取出。

请记住,编写正确的锁定代码需要程序中所有锁的全局知识,所有线程上的所有操作都可能在每个可能的顺序中将它们取出。这就是为什么要做到这一点很难的原因;大多数编程任务只需要本地知识。锁需要全局了解整个程序,包括您未编写的部分。如果某个第三方dll正在对某个对象进行锁定并且您的代码正在等待同一个对象,那么您必须同意该第三方代码的正确锁定顺序选择。

这是最可能的原因。有一个不太可能但可能的其他原因,即有时您在取出锁定和解锁finally块执行之间中止线程。这将导致C#3及以下的僵局;我们已经在C#4中修复了代码生成器,因此不再发生这种情况。这里故事的寓意虽然不是“使用C#4”,但它“不会中止线程,特别是不要中止可能锁定某些东西的线程”。线程中止应该仅用作最后的手段,无论如何都要进行此过程。