Как синхронизировать между прослушиванием / отправкой потока клиента TCP и основным исполнением? - PullRequest
0 голосов
/ 03 ноября 2011

У меня есть простая служба Windows, которая запускается и запускает поток, который прослушивает / получает сердцебиение через tcp / ip.Мне трудно найти способы синхронизации между получением информации из потока TCP и использованием этого значения для обновления чего-либо в основном потоке.

Я пытаюсь использовать метод thread.sleep и продолжаю его зацикливатьв течение нескольких раз, ожидая ответ от потока и затем получая значение, но этот метод кажется немного нестабильным, когда метод иногда работает, а иногда нет.

, так что хороший способ синхронизации междуэти двое?в основном я хочу запустить прослушивающий поток tcp, получить конкретное значение и обновить основную программу.

- это функция приема и функция, которую я использовал для запуска потока.ps: я совершенно нуби, когда дело доходит до tcp / ip и c #, поэтому любые комментарии к любой части кода или дизайну приветствуются:)

public virtual void Receive()
        {
            string eventMessage = string.Empty;
            int bytesRcvd = 0;
            int totalBytesRcvd = 0;
            byte[] byteBuffer = new byte[maxBufferSize];
            NetworkStream listenStream;
            try
            {
                if (client.Connected)
                {
                    listenStream = client.GetStream();    
                }
                else
                {
                    return;
                }

                while (true)
                {                
                    //message that is slot in from the object will get sent here.
                    if (!string.IsNullOrEmpty(MessageToSend))
                    {
                        Send(MessageToSend);
                        MessageToSend = string.Empty;
                    }

                    // must convert it back and look for the delimiter, cannot wait for the three heartbeat to pass
                    string leftoverMsg = string.Empty;

                    bytesRcvd = listenStream.Read(byteBuffer, totalBytesRcvd, maxBufferSize - totalBytesRcvd);
                    totalBytesRcvd += bytesRcvd;

                    //if more than heart beat size, can process to see if it's a heartbeat and proceed to send
                    if (totalBytesRcvd > msgHeartbeatSize)
                    {
                        eventMessage = Encoding.ASCII.GetString(byteBuffer, 0, totalBytesRcvd);
                        ProcessMessage(eventMessage, ref leftoverMsg, ref totalBytesRcvd, ref byteBuffer);
                    }
                }
            }
            catch (ThreadAbortException thEx)
            {
                //do nothing as main thread has aborted and waiting to close
                logger.Info(Thread.CurrentThread.Name + " is stopped. ");
            }
            catch (Exception exce)
            {
                bIsActive = false;
                logger.Error(exce);
                CleanUp();
            }
            finally
            {
                logger.Info(String.Format("Thread {0} Exiting. ", Thread.CurrentThread.Name));
            }
        }

public virtual void StartReceivingThread()
        {
            Thread thrReceive = new Thread(Receive);
            try
            {
                if (!bIsActive && Connect())
                {
                    //NOTE: exception thrown by a thread can only be captured by that thread itself
                    //start a listen thread
                    //wait until heartbeat message is accepted

                    thrReceive.Name = "thr" + serviceType.Name;
                    thrReceive.Start();
                    bIsActive = true;

                    //wait to get the heartbeat message
                    for (int i = 0; i < maxRetry; i++)
                    {
                        Thread.Sleep(maxTimeOutValue);
                        if (bIsReceivingHeartbeat)
                            break;
                    }
                    //if nothing happens close the connection and try again
                    if (!bIsReceivingHeartbeat)
                    {
                        bIsActive = false;
                        CleanUp();
                        logger.Info("Closing  receiver thread - " + thrReceive.Name);
                    }
                    else
                    {
                        logger.Info("Starting  receiver thread - " + thrReceive.Name);
                    }
                }


            }
            catch(Exception ex)
            {
                logger.Error(ex);
            }
            //finally
            //{
            //    logger.Info("Exiting  receiver thread - " + thrReceive.Name);
            //}
        }

Ответы [ 2 ]

1 голос
/ 03 ноября 2011

Полагаю, bIsReceivingHeartbeat является bool переменной-членом класса.Если значение, измененное в одном потоке (получателе), не видно в другом потоке, это, скорее всего, связано с барьером памяти.Я говорю это из своего фона Java, но это, скорее всего, верно и для .net.

Попробуйте объявить переменные volatile или используйте свойство и синхронизируйте метод получения и установки:

private bool bIsReceivingHeartbeat;
public bool IsReceivingHeartbeat
{
    [MethodImpl(MethodImplOptions.Synchronized)]
    get { return bIsReceivingHeartbeat; }
    [MethodImpl(MethodImplOptions.Synchronized)]
    set { bIsReceivingHeartbeat = value; }
}

И в коде вызова:

if (!IsReceivingHeartbeat) ....

Я пишу из Java-фона, но ситуация, скорее всего, похожа

0 голосов
/ 03 ноября 2011

(Похоже, вы также разместили этот код на refactormycode.com.)

В любом случае, вместо цикла с задержкой сна, я рекомендую использовать объект Event, который пульсирует кодом, который устанавливает IsReceivingHeartbeat.См. Классы ManualResetEvent и AutoResetEvent в MSDN.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...