【问题标题】:ManualResetEvent issue on WinXP embeddedWinXP 嵌入式上的 ManualResetEvent 问题
【发布时间】:2012-04-17 14:21:37
【问题描述】:

我在使用带超时参数的 ManualResetEvent 类时遇到问题。此问题专门发生在 WinXP 嵌入式平台上。该代码在其他 Windows 平台上完美运行。我正在与 TCP 服务器通信。在我的客户端代码中,我连接到服务器并生成一个新线程,我的工作是持续监控接收套接字的数据。我在主线程中发送数据。下面附上代码sn-p:

internal void initSocket()
{
   .....
   .....
   if (socket.Connected)
   {
      Tracing.info("Connected to server");
      ReceiveThread = new Thread(new    ThreadStart(StartReceiving));
      ReceiveThread.Start();
    }
}

/// <summary>
/// Sends a request to Server and waits for its response.
/// </summary>
/// <param name="msg"></param>
/// <param name="timeout">Timeout time, when </param>
/// <returns></returns>
private CdcMessage sendSync(CdcMessage msg, int timeout)
{
    resultMessage = null;

    // store current messageId...
    resultMessagePackageId = msg.MessageId;

    String msgToSend = msg.serialize();

    Tracing.debug("SEND    : >> " + msgToSend);
    socketWriter.WriteLine(msgToSend);

    // Wait for response from read thread...
    resultReceivedEvent = new  ManualResetEvent(false);
    bool bReponseSent = resultReceivedEvent.WaitOne(timeout);

    if (!bReponseSent)
    {
        resultMessage = null;
    }

    return resultMessage;

}

/// <summary>
/// Thread function which continuously checks for the 
/// data from server. It will read the data only if it
/// is available
/// </summary>
public void StartReceiving()
{
    while (Connected)
    {
        try
        {
            Thread.Sleep(100);

            String response = socketReader.ReadLine();

            Tracing.info("Raw data received = " + response);

            resultMessage = CdcMessage.deserialize(response);

            Tracing.info("Deserialized response =  " + resultMessage);

            if (resultMessage == null)
            {
                continue;
            }
            else if (resultMessage.IsHeartbeat)
            {
                Tracing.debug("Heartbeat");
                socketWriter.WriteLine(response);
            }
            else if (!resultMessage.MessageId.Equals(resultMessagePackageId))
            {
                // not the correct package id...reject...
                Tracing.warn("REJECTED: Package-ID: " + resultMessage.MessageId);
                continue;
            }
            else
            {
                resultReceivedEvent.Set();
                Tracing.info("StartReceiving() : Received data");
                Tracing.debug("RECEIVED: >> " + response);
            }
        }
        catch (NullReferenceException nre)
        {
            Tracing.error("StartReceiving(): Socket doesn't exist!", nre);
            close();
            break;
        }
        catch (ObjectDisposedException ode)
        {
            Tracing.error("StartReceiving(): Socket is disposed!", ode);
            close();
            break;
        }
        catch (IOException ex)
        {
            Tracing.error("StartReceiving(): Socket IO-Exception!", ex);
            close();
            break;
        }
    }
}

我已经强调了代码的重要方面。据观察,WaitOne(timeout) 函数在大多数 Windows 操作系统上都可以正常工作。但是在 XP 嵌入式上,我观察到一个问题。 WaitOne 几乎立即返回,没有从接收线程接收到数据。

我所做的是通过将 -1 传递给 WaitOne,将超时设置为 INFINITE。在这种情况下,我可以解决问题。但这会产生其他副作用(例如,如果服务器关闭,则 WaitOne 永远不会返回!)

有人可以帮我解决这个问题吗?

【问题讨论】:

  • 代码中肯定存在线程竞争。您创建 MRE 为时已晚,可能会在您创建它之前收到响应。使用太低的超时也可以做到这一点,使用秒,而不是毫秒。

标签: c# .net windows-7 windows-xp-embedded manualresetevent


【解决方案1】:

我不确定我是否正确理解了您的代码,但是这些行

socketWriter.WriteLine(msgToSend);
resultReceivedEvent = new  ManualResetEvent(false);
bool bReponseSent = resultReceivedEvent.WaitOne(timeout);

对我来说看起来很奇怪。我认为这样会更好:

resultReceivedEvent.Reset();
socketWriter.WriteLine(msgToSend);
bool bReponseSent = resultReceivedEvent.WaitOne(timeout);

如果在创建新ManualResetEvent 之前设置了旧ManualResetEvent,则可能存在潜在的竞争条件。似乎没有理由在此处创建 ManualResetEvent 的新实例。只需在旧实例上调用 Reset,并确保在发送消息之前重置它。

【讨论】:

  • 感谢您的提示。我将在 XP-E 上重新检查,并让您知道我的发现
猜你喜欢
  • 1970-01-01
  • 2018-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多