锁定专用锁定对象会导致死锁



昨天我遇到了一个奇怪的问题,这让我很头疼。我有一个带有server类的服务器应用程序,该类又是从Connection类派生的。Connection类提供有关连接状态和关闭连接的可能性的信息

public bool Connected
{
get
{
if (connection != null)
{
lock (lockObject)
{
bool blockingState = connection.Blocking;
try
{
connection.Blocking = false;
connection.Send(new byte[1], 1, 0);
}
catch (SocketException e)
{
if (!e.NativeErrorCode.Equals(10035))
{
return false;
}
//is connected, but would block
}
finally
{
connection.Blocking = blockingState;
}
return connection.Connected;
}
}
return false;
}
}
public virtual void CloseConnection()
{
if (Connected)
{
lock (lockObject)
{
connection.Close();
}
}
}

Server类负责实际发送数据

private void ConnectAndPollForData()
{
try
{
TcpListener listener = new TcpListener(Port);
listener.Start();
while (true)
{
connection = listener.AcceptSocket();
string currentBuffr = string.Empty;
const int READ_BUFFER_SIZE = 1024;
byte[] readBuffr = new byte[READ_BUFFER_SIZE];
while (Connected)
{
int bytesReceived;
lock (lockObject)
{
bytesReceived = connection.Receive(readBuffr, READ_BUFFER_SIZE, SocketFlags.None);
}
currentBuffr += ASCIIEncoding.ASCII.GetString(readBuffr, 0, bytesReceived);
//do stuff
}
}
catch(ThreadAbortException)
{
Thread.ResetAbort();
}
finally
{
}
}
public void SendString(string stringToSend)
{
stringToSend += "rn";

if(Connected)
{
lock(lockObject)
{
connection.Send(ASCIIEncoding.UTF7.GetBytes(stringToSend));
}
}
}

没有其他对连接对象的显式访问。ConnectAndPollForData函数在单独的线程中执行。每当我在这个版本中运行主机时(我目前使用的是非线程安全版本,这会导致其他问题),它都会在通过TCP接收到相当多的行之后挂起。暂停调试器显示,一个线程试图在Connected的锁中执行代码,而另一个线程则试图在ConnectAndPollForData的锁中接收数据。这种行为对我来说似乎很奇怪,因为我希望在第一个锁中执行代码,然后再执行第二个锁。当使用像Deadlocking lock()方法或';死锁';只有一个锁定的对象?但这里的情况有点不同,因为在我的情况下(我认为)锁中的代码不应该发出任何事件,这些事件本身试图获得对象的锁。

假设它首先在第二个方法中获得锁。因此,持有锁,并等待数据。目前尚不清楚这是直接接收第一种方法发送的数据,还是在寻找来自无关服务器的回复——对第一种方法中发送的消息的回复。但不管怎样,我假设在发送出站消息之前不会有数据传入。

现在考虑一下:出站消息不能发送,因为您持有独占锁。

所以,是的,你已经陷入僵局了。基本上,不要那样做。入站和出站套接字操作之间不需要同步,即使在同一个套接字上也是如此。由于在同一个套接字上有并发的读取器或并发的编写器是没有意义的,我猜你实际上根本不需要这些lock

最新更新