Проблема ManualResetEvent на встроенной WinXP

У меня возникла проблема с использованием класса ManualResetEvent с параметром тайм-аута. Эта проблема возникает только на встроенной платформе WinXP. Код отлично работает на других платформах Windows. Я общаюсь с TCP-сервером. В моем клиентском коде я подключаюсь к серверу и создаю новый поток, задача которого заключается в постоянном мониторинге принимающего сокета для данных. Я отправляю данные в основной поток. Фрагмент кода прикреплен ниже:

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 embedded наблюдаю проблему. WaitOne почти немедленно возвращается без данных, полученных от потока приема.

Что я сделал, так это сделал тайм-аут как INFINITE, передав -1 в WaitOne. В этом случае я могу решить проблему. Но это создает другие побочные эффекты (например, если сервер был выключен, то WaitOne никогда не возвращается!)

Может ли кто-нибудь помочь мне в решении этой проблемы?


person this-Me    schedule 17.04.2012    source источник
comment
В коде определенно есть гонка потоков. Вы создаете MRE слишком поздно, ответ может быть получен до его создания. Использование слишком малого тайм-аута тоже может сделать это, используйте секунды, а не миллисекунды.   -  person Hans Passant    schedule 17.04.2012


Ответы (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. Просто вызовите Reset на старом экземпляре и убедитесь, что вы сбросили его перед отправкой сообщения.

person ken    schedule 17.04.2012
comment
Спасибо за подсказку. Я перепроверю это на XP-E и сообщу вам о своих выводах. - person this-Me; 18.04.2012