ReaderWriterLockSlim 抛出 LockRecursionException Socket.BeginReceive
ReaderWriterLockSlim throws LockRecursionException with Socket.BeginReceive
给定下面的简单套接字客户端 class,将其连接到 TCP 服务器(我使用 SocketTest3,可在线免费获得)。然后断开服务器并稍等片刻。你应该得到一个 LockRecursionException
.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace SocketRwlTest
{
public class SocketRwlTest
{
private Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
private readonly ReaderWriterLockSlim rwl = new ReaderWriterLockSlim();
private const int maxLength = 200;
public SocketRwlTest(IPAddress address, ushort port)
{
client.Connect(new IPEndPoint(address, port));
ReceiveOne();
}
private void ReceiveOne()
{
rwl.EnterReadLock();
try
{
var inArray = new byte[maxLength];
client.BeginReceive(inArray, 0, maxLength, 0,
new AsyncCallback(ReceivedCallback),
inArray);
}
finally
{
rwl.ExitReadLock();
}
}
private void ReceivedCallback(IAsyncResult ar)
{
client.EndReceive(ar);
ReceiveOne();
}
}
}
我不明白为什么会出现在给出的简化示例中。我知道我应该在收到零长度消息后立即停止调用 ReceiveOne
,但这更像是一个练习。我想知道类似的错误是否可以在后台保持持续的回调 运行 流并窃取资源而不会发生明显的坏事。我必须承认我没有预料到 这个 特殊例外。
问题一:为什么会出现这种情况? BeginXYZ
方法是否允许在同一线程上立即执行回调?如果是这样,谁能说在正常运行时不会发生这种情况?
问题 2:在这种情况下,有没有办法在保持 "desired" 行为的同时避免出现此异常?我的意思是触发一个不间断的回调流。
我正在使用 Visual Studio 2010 和 .NET 4。
Question 1: Why does this happen? Are BeginXYZ methods perhaps allowed to execute callbacks instantly, on the same thread? If that's the case, who's to say this couldn't happen during normal runtime?
如 所述,BeginReceive()
方法 不需要 异步执行。如果数据可用,它 将 同步执行,在同一个线程中调用回调委托。根据定义,这是一个递归调用,因此与 non-recursive 锁定对象的使用不兼容(例如您在此处使用的 ReaderWriterLockSlim
).
这肯定会发生"during normal runtime"。我不确定我是否理解你问题的第二部分。谁能说这不可能发生?没有人。 可以发生。
Question 2: Are there ways to avoid getting this exception while still maintaining the "desired" behaviour in this case? I mean fire a non-stopping stream of callbacks.
恐怕我也不知道你说的"fire a non-stopping stream of callbacks"是什么意思。
一个明显的解决方法是通过将 LockRecursionPolicy.SupportsRecursion
传递给其构造函数来启用对 ReaderWriterLockSlim
对象的递归。或者,您可以在尝试获取锁之前检查 IsReadLockHeld
属性。
从您的代码示例中并不清楚为什么您拥有锁,更不用说为什么以这种特定方式使用它。正确的解决方案可能是在调用 BeginReceive()
时根本不持有锁。仅在处理 EndReceive()
.
的结果时使用它
给定下面的简单套接字客户端 class,将其连接到 TCP 服务器(我使用 SocketTest3,可在线免费获得)。然后断开服务器并稍等片刻。你应该得到一个 LockRecursionException
.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace SocketRwlTest
{
public class SocketRwlTest
{
private Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
private readonly ReaderWriterLockSlim rwl = new ReaderWriterLockSlim();
private const int maxLength = 200;
public SocketRwlTest(IPAddress address, ushort port)
{
client.Connect(new IPEndPoint(address, port));
ReceiveOne();
}
private void ReceiveOne()
{
rwl.EnterReadLock();
try
{
var inArray = new byte[maxLength];
client.BeginReceive(inArray, 0, maxLength, 0,
new AsyncCallback(ReceivedCallback),
inArray);
}
finally
{
rwl.ExitReadLock();
}
}
private void ReceivedCallback(IAsyncResult ar)
{
client.EndReceive(ar);
ReceiveOne();
}
}
}
我不明白为什么会出现在给出的简化示例中。我知道我应该在收到零长度消息后立即停止调用 ReceiveOne
,但这更像是一个练习。我想知道类似的错误是否可以在后台保持持续的回调 运行 流并窃取资源而不会发生明显的坏事。我必须承认我没有预料到 这个 特殊例外。
问题一:为什么会出现这种情况? BeginXYZ
方法是否允许在同一线程上立即执行回调?如果是这样,谁能说在正常运行时不会发生这种情况?
问题 2:在这种情况下,有没有办法在保持 "desired" 行为的同时避免出现此异常?我的意思是触发一个不间断的回调流。
我正在使用 Visual Studio 2010 和 .NET 4。
Question 1: Why does this happen? Are BeginXYZ methods perhaps allowed to execute callbacks instantly, on the same thread? If that's the case, who's to say this couldn't happen during normal runtime?
如 BeginReceive()
方法 不需要 异步执行。如果数据可用,它 将 同步执行,在同一个线程中调用回调委托。根据定义,这是一个递归调用,因此与 non-recursive 锁定对象的使用不兼容(例如您在此处使用的 ReaderWriterLockSlim
).
这肯定会发生"during normal runtime"。我不确定我是否理解你问题的第二部分。谁能说这不可能发生?没有人。 可以发生。
Question 2: Are there ways to avoid getting this exception while still maintaining the "desired" behaviour in this case? I mean fire a non-stopping stream of callbacks.
恐怕我也不知道你说的"fire a non-stopping stream of callbacks"是什么意思。
一个明显的解决方法是通过将 LockRecursionPolicy.SupportsRecursion
传递给其构造函数来启用对 ReaderWriterLockSlim
对象的递归。或者,您可以在尝试获取锁之前检查 IsReadLockHeld
属性。
从您的代码示例中并不清楚为什么您拥有锁,更不用说为什么以这种特定方式使用它。正确的解决方案可能是在调用 BeginReceive()
时根本不持有锁。仅在处理 EndReceive()
.