为事先检查为 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。

但是,在这种情况下,我有两个问题:

  1. 为什么会抛出异常,如果我们在调用 Sent 方法之前有几行是为了检查对象是否为 null 并锁定该对象以防止任何其他线程处理它?

  2. 为什么没有捕获异常?

    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”作为锁时。前一个线程完成空值检查并休眠,然后下一个线程开始执行空值赋值代码并休眠,然后上下文切换到前一个线程,并引发空引用异常。