如何在侦听/发送tcp客户端线程和主执行之间同步

本文关键字:线程 执行 同步 之间 客户端 tcp 发送 | 更新日期: 2023-09-27 18:13:29

我有一个简单的Windows服务,它运行并启动一个线程,通过tcp/ip侦听/接收心跳。我很难找到从TCP线程获取信息和使用该值更新主线程中的内容之间同步的方法。

我尝试使用线程。Sleep方法并继续循环它几次,同时等待从线程返回的答案,然后获得值,但该方法似乎有点不稳定,该方法有时工作,有时不工作。

那么在这两者之间同步的好方法是什么呢?基本上我想做的是启动侦听TCP线程,获取特定值并更新主程序。

附件是receive函数和我用来启动线程的函数。附言:我对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);
            //}
        }

如何在侦听/发送tcp客户端线程和主执行之间同步

我假设bIsReceivingHeartbeat是该类的bool成员变量。如果在一个线程(接收者)中更改的值在另一个线程中不可见,这很可能是由于内存屏障。我是从我的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背景写的,但情况很可能类似

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

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