2012-04-17 8 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 OSで問題なく動作することが確認されています。しかし、埋め込まれたXPでは、私は問題を遵守します。 WaitOneは、受信スレッドから受信したデータがない場合、ほとんどすぐに戻ります。

私がしたことは、-1をWaitOneに渡すことによってINFINITEとしてタイムアウトを行いました。この場合、私は問題を解決することができました。しかし、これは他の副作用を引き起こします(例えば、サーバがシャットダウンした場合、WaitOneは返されません)。

誰かがこの問題の解決に手伝ってくれますか?

+0

コードにスレッドレースがあります。あまりにも遅れてMREを作成すると、作成する前に*応答を受け取ることができます。低すぎるタイムアウトを使用すると、ミリ秒ではなく秒を使用することもできます。 –

答えて

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で再確認し、私の知見を知らせます –

関連する問題