2011-11-03 22 views
0

我有一个简单的Windows服务,运行并启动一个线程,通过tcp/ip监听/接收心跳线。我很难找到从tcp线程获取信息并使用该值更新主线程中的某些内容之间同步的方法。如何在侦听/发送tcp客户端线程和主执行之间进行同步?

我尝试使用一个thread.sleep方法,并在等待线程的回应,然后获取值时继续循环几次,但该方法似乎有点挥发,有时方法工作有时候不是。

那么在这两者之间同步的好方法是什么? 基本上我想要做的就是启动监听tcp线程,获取具体的值并更新主程序。

附加的是接收函数和我用来启动线程的函数。 PS:我是一个完全noobie当涉及到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); 
      //} 
     } 

回答

1

更多我认为bIsReceivingHeartbeatbool成员类的变量。如果在一个线程(接收器)中更改的值在另一个线程中不可见,这很可能是由于内存屏障。我是从我的Java背景来说的,但这在.net中也是很可能的。

尝试声明变量volatile或使用性质,使getter和setter同步:

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

而在调用代码:

if (!IsReceivingHeartbeat) .... 

我从Java的背景,但情况写最有可能类似

+0

是的。毫米,任何警告,我需要小心使用易失性? – melaos

+0

有很多东西比较易失性和同步。我通常更喜欢后者,但我不知道为什么。一个有据可查的警告涉及'volataileVairable ++'这样的用法 - 两个线程都可以读取相同的值并将其设置为相同的值,净结果是变量只会增加一次而不是两次。我很想知道这是否解决了您的问题或其他问题是根本原因。 –

0

(看起来你也在refactormycode.com上发布了这个代码。)

无论如何,我建议使用由设置IsReceivingHeartbeat的代码脉冲的Event对象,而不是带有睡眠延迟的循环。请参阅MSDN中的ManualResetEvent和AutoResetEvent类。

+0

是的,我做了,因为我想得到一些答案这个设计/问题,但我发布那里,让人们可以评论任何其他事情。 – melaos