2012-04-17 72 views
0

我在使用帶有超時參數的ManualResetEvent類時遇到問題。 WinXP嵌入式平臺上特別發生此問題。該代碼在其他Windows平臺上完美工作。我正在與TCP服務器進行通信。在我的客戶端代碼中,我連接到服務器併產生一個新線程,所以工作就是持續監視數據的接收套接字。我在主線程中發送數據。代碼片段如下所示:WinXP中的ManualResetEvent問題嵌入式

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(超時)功能在大多數Windows操作系統上沒有任何問題。但在嵌入式XP中,我觀察到一個問題。 WaitOne幾乎立即返回,沒有從接收線程收到數據。

我所做的是通過將-1傳遞給WaitOne來使INFINITE的超時。在這種情況下,我可以解決問題。但是這會產生其他副作用(例如,如果服務器已關閉,那麼WaitOne永遠不會返回!)

有人可以幫我解決這個問題嗎?

+0

代碼中絕對存在線程競爭。您創建MRE的時間太晚了,您可以在*創建之前收到回覆*。使用太低的超時也可以,使用秒,而不是毫秒。 – 2012-04-17 18:02:41

回答

2

我不知道我正確地理解你的代碼,但線

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

看起來很奇怪我。我認爲這將是更好的:

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

如果創建新的前舊的ManualResetEvent被設定有可能是潛在的競爭狀態。在這裏似乎沒有理由創建一個新的ManualResetEvent實例。只需在舊實例上調用Reset,並確保在發送消息之前將其重置。

+0

感謝您的提示。我將在XP-E上重新檢查這一點,並讓你知道我的發現 – 2012-04-18 08:08:25