为事先检查为 null 并被锁定的对象(即套接字)抛出 NullReferenceException
NullReferenceException thrown for an object (i.e. socket) that was checked to be null beforehand and is locked
我敢肯定这是被忽视的愚蠢行为,但我在行 _clientSocket.Send(Encoding.ASCII.GetBytes(data));
上抛出了 System.NullReferenceException 异常并且可以确认_clientSocket
抛出异常时为null。
但是,在这种情况下,我有两个问题:
为什么会抛出异常,如果我们在调用 Sent 方法之前有几行是为了检查对象是否为 null 并锁定该对象以防止任何其他线程处理它?
为什么没有捕获异常?
private bool SendToServer(string data)
{
Logger.Log($"[{_clientID}] sending the following to server: {data}", LoggingSeverity.trace);
if (_clientSocket == null)
{
Logger.Log($"[{_clientID}] send failure. Socket not initialized.", LoggingSeverity.warning);
return false;
}
lock (_clientSocket)
{
bool sendSuccessful = true;
try
{
_clientSocket.Send(Encoding.ASCII.GetBytes(data));
}
catch (Exception ex)
{
Logger.Log($"[{_clientID}] client send exception: {ex.Message}", LoggingSeverity.warning);
sendSuccessful = false;
}
if (!sendSuccessful)
{
try
{
_clientSocket.Close();
}
catch (Exception ex)
{
Logger.Log($"[{_clientID}] client close exception: {ex.Message}", LoggingSeverity.warning);
}
_clientSocket = null;
return false;
}
}
Thread.Sleep(1000);
return true;
}
谢谢大家抽空来看,反馈意见等等
关键区域是你的“_clientSocket”亲爱的。您应该避免对锁定对象使用“_clientSocket”。
这样做:
private static readonly _lock = new object();
private bool SendToServer(string data)
{
Logger.Log($"[{_clientID}] sending the following to server: {data}", LoggingSeverity.trace);
lock (_lock)
{
if (_clientSocket == null)
{
Logger.Log($"[{_clientID}] send failure. Socket not initialized.", LoggingSeverity.warning);
return false;
}
bool sendSuccessful = true;
try
{
_clientSocket.Send(Encoding.ASCII.GetBytes(data));
}
catch (Exception ex)
{
Logger.Log($"[{_clientID}] client send exception: {ex.Message}", LoggingSeverity.warning);
sendSuccessful = false;
}
if (!sendSuccessful)
{
try
{
_clientSocket.Close();
}
catch (Exception ex)
{
Logger.Log($"[{_clientID}] client close exception: {ex.Message}", LoggingSeverity.warning);
}
_clientSocket = null;
return false;
}
}
Thread.Sleep(1000);
return true;
}
主要问题出现在使用“_clientSocket”作为锁时。前一个线程完成空值检查并休眠,然后下一个线程开始执行空值赋值代码并休眠,然后上下文切换到前一个线程,并引发空引用异常。
我敢肯定这是被忽视的愚蠢行为,但我在行 _clientSocket.Send(Encoding.ASCII.GetBytes(data));
上抛出了 System.NullReferenceException 异常并且可以确认_clientSocket
抛出异常时为null。
但是,在这种情况下,我有两个问题:
为什么会抛出异常,如果我们在调用 Sent 方法之前有几行是为了检查对象是否为 null 并锁定该对象以防止任何其他线程处理它?
为什么没有捕获异常?
private bool SendToServer(string data) { Logger.Log($"[{_clientID}] sending the following to server: {data}", LoggingSeverity.trace); if (_clientSocket == null) { Logger.Log($"[{_clientID}] send failure. Socket not initialized.", LoggingSeverity.warning); return false; } lock (_clientSocket) { bool sendSuccessful = true; try { _clientSocket.Send(Encoding.ASCII.GetBytes(data)); } catch (Exception ex) { Logger.Log($"[{_clientID}] client send exception: {ex.Message}", LoggingSeverity.warning); sendSuccessful = false; } if (!sendSuccessful) { try { _clientSocket.Close(); } catch (Exception ex) { Logger.Log($"[{_clientID}] client close exception: {ex.Message}", LoggingSeverity.warning); } _clientSocket = null; return false; } } Thread.Sleep(1000); return true; }
谢谢大家抽空来看,反馈意见等等
关键区域是你的“_clientSocket”亲爱的。您应该避免对锁定对象使用“_clientSocket”。 这样做:
private static readonly _lock = new object();
private bool SendToServer(string data)
{
Logger.Log($"[{_clientID}] sending the following to server: {data}", LoggingSeverity.trace);
lock (_lock)
{
if (_clientSocket == null)
{
Logger.Log($"[{_clientID}] send failure. Socket not initialized.", LoggingSeverity.warning);
return false;
}
bool sendSuccessful = true;
try
{
_clientSocket.Send(Encoding.ASCII.GetBytes(data));
}
catch (Exception ex)
{
Logger.Log($"[{_clientID}] client send exception: {ex.Message}", LoggingSeverity.warning);
sendSuccessful = false;
}
if (!sendSuccessful)
{
try
{
_clientSocket.Close();
}
catch (Exception ex)
{
Logger.Log($"[{_clientID}] client close exception: {ex.Message}", LoggingSeverity.warning);
}
_clientSocket = null;
return false;
}
}
Thread.Sleep(1000);
return true;
}
主要问题出现在使用“_clientSocket”作为锁时。前一个线程完成空值检查并休眠,然后下一个线程开始执行空值赋值代码并休眠,然后上下文切换到前一个线程,并引发空引用异常。