IdHTTP连接关闭时出现访问冲突

5

Indy 10:

两个线程,线程1正在调用TIdHTTP上的Get并阻塞读取数据。线程2将在同一个TIdHTTP上调用disconnect以中断Get。

我在TIdHTTP上使用摘要认证,偶尔会出现AV。

线程1的调用堆栈:

40491D [system.pas][System][@ClassDestroy][8989]
69EF2B [..\..\common\IdAuthenticationDigest.pas][IdAuthenticationDigest][TIdDigestAuthentication.Destroy][109]
404567 [system.pas][System][TObject.Free][8313]
6A2B69 [..\..\Common\IdHTTP.pas][IdHTTP][TIdCustomHTTP.DoOnDisconnected][1587]
534574 [IdTCPConnection.pas][IdTCPConnection][TIdTCPConnection.Disconnect][532]
534B3B [IdTCPConnection.pas][IdTCPConnection][TIdTCPConnection.Disconnect][767]
6A3FB3 [..\..\Common\IdHTTP.pas][IdHTTP][TIdCustomHTTP.DoRequest][2101]

线程2的调用栈:

402BA3 [system.pas][System][@FreeMem][2477]
404521 [system.pas][System][TObject.FreeInstance][8294]
40491D [system.pas][System][@ClassDestroy][8989]
69EF2B [..\..\common\IdAuthenticationDigest.pas][IdAuthenticationDigest]        [TIdDigestAuthentication.Destroy][109]
404567 [system.pas][System][TObject.Free][8313]
6A2B69 [..\..\Common\IdHTTP.pas][IdHTTP][TIdCustomHTTP.DoOnDisconnected][1587]
534574 [IdTCPConnection.pas][IdTCPConnection][TIdTCPConnection.Disconnect][532]
534B3B [IdTCPConnection.pas][IdTCPConnection][TIdTCPConnection.Disconnect][767]

基本上在DoRequest的结尾会进入到一个断开连接的状态。似乎在断开连接时存在竞争条件,尝试释放Request.Authentication。
已下载Indy 10的最新代码,并查看了代码,我认为行为应该是相同的。
我认为从另一个线程调用断开连接是推荐的使用模式,我错了吗?这是Indy中的一个bug吗?看起来需要锁定断开连接,但很难看出可能会引起的死锁。还有其他人遇到过这个问题吗?

你不能这样使用Indy。你应该在一个线程中操作该对象。你想要实现什么目标? - whosrdaddy
我不确定,可以参考这个帖子,似乎这是中断GET请求的预期方式。http://www.delphigroups.info/2/4/208119.html - Mike Davis
@whosrdaddy:不是这样的。Indy旨在支持这种用法。实际上,Indy自己的一些组件,比如TIdTelnet,在内部执行的正是Mike正在做的事情。除非使用超时,否则从另一个线程断开套接字是中止阻塞I/O操作的唯一方法。 - Remy Lebeau
那么这一定是一个锁定 bug 吗? - whosrdaddy
1个回答

6
是的,你遇到了一个竞态条件,当套接字断开连接时,两个线程都试图释放相同的Request.Authentication对象两次。根据堆栈跟踪,两个线程必须在完全相同的时间断开套接字,因为Disconnect()只有在IOHandler仍然打开时才调用DoOnDisconnect(),而在调用DoOnDisconnect()之前,IOHandler已关闭。
你可以尝试使用OnStatus事件进入线程安全锁,如关键部分或互斥体,在hsDisconnecting状态下离开锁定,并在hsDisconnected状态下保持锁定。在这些状态之间调用IOHandler.Close()DoOnDisconnect(),这样就可以有效地序列化您的线程,使它们不能再同时断开套接字和释放Request.Authentication对象。

1
谢谢,这比我想象中的更优雅。我会在相同的压力情况下尝试一下,但看起来很不错。 - Mike Davis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接