2012-04-17 5 views
0

Timeout 매개 변수와 함께 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 (timeout) 기능은 대부분의 Windows OS에서 문제없이 작동합니다. 하지만 임베디드 XP에서는 문제가 발생합니다. WaitOne은 수신 스레드로부터 수신 된 데이터가 없을 때 거의 즉시 반환됩니다.

내가 한 것은 WaitOne에 -1을 전달하여 INFINITE로 제한 시간을 만들었습니다. 이 경우 문제를 해결할 수 있습니다. 하지만 이로 인해 다른 부작용이 생깁니다 (예 : 서버가 종료 된 경우 WaitOne이 반환되지 않음)

누군가가이 문제를 해결하는 데 도움을 줄 수 있습니까?

+0

확실히 코드에 스레딩 레이스가 있습니다. MRE를 너무 늦게 생성하면 응답을 * 생성하기 전에받을 수 있습니다. 시간 초과가 너무 낮 으면 너무 길어질 수 있으므로 밀리 초가 아닌 초를 사용하십시오. –

답변

2

는 내가 제대로 코드를 이해 모르겠지만, 라인

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

나에게 이상하게 보일. 나는이 더 좋을 거라 생각 : 새로운 하나를 만들기 전에 오래된 ManualResetEvent가 설정됩니다 경우

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

잠재적 인 경쟁 조건이있을 수 있습니다. 여기서 ManualResetEvent의 새 인스턴스를 만드는 이유는없는 것 같습니다. 이전 인스턴스에서 Reset으로 전화를 걸고 메시지를 보내기 전에 재설정해야합니다.

+0

힌트를 보내 주셔서 감사합니다. XP-E에서 다시 확인하고 내 결과를 알려 드리겠습니다. –