[英]How to sync between a listening/sending tcp client thread and the main execution?
i have a simple windows service which runs and starts a thread which listen/receive heartbeat via tcp/ip. 我有一个简单的Windows服务,该服务运行并启动一个线程,该线程通过tcp / ip侦听/接收心跳。 i'm having a hard time finding ways to sync between getting information from the tcp thread and using that value to update something in the main thread.
我很难找到从tcp线程获取信息和使用该值更新主线程中的内容之间进行同步的方法。
i try to use a thread.sleep method and keep on looping it for a few times while awaiting the answer back from the thread and then getting the value, but that method seems to be a bit volatile with the method sometimes working and sometimes not. 我尝试使用thread.sleep方法,并在等待它从线程返回答案然后获取值的同时继续循环几次,但是该方法似乎有些不稳定,有时该方法有时有效,而有时则无效。
so what's a good way to sync between these two? 那么在这两者之间进行同步的一种好方法是什么? basically what i want to do is to start the listening tcp thread, get specific value and the update the main program.
基本上我想做的是启动监听tcp线程,获取特定值并更新主程序。
attached are the receive function and the function which i used to start the thread. 附带的是接收功能和我用来启动线程的功能。 ps: i'm a totally noobie when it comes to tcp/ip and c# so any comments on any part of the code or the design is more than welcome :)
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);
//}
}
I assume bIsReceivingHeartbeat
is a bool
member variable of the class. 我假设
bIsReceivingHeartbeat
是bIsReceivingHeartbeat
的bool
成员变量。 If the value changed in one thread (receiver) is not visible in the other thread this is most likely due to memory barrier. 如果一个线程(接收器)中更改的值在另一线程中不可见,则最有可能是由于内存屏障。 I am saying this from my Java background but this is most likely true in .net as well.
我是从Java背景讲这个的,但这在.net中也很可能也是这样。
Try declaring the variables volatile
or use a property and make the getter and setter synchronized: 尝试将变量声明为
volatile
或使用属性,并使getter和setter同步:
private bool bIsReceivingHeartbeat;
public bool IsReceivingHeartbeat
{
[MethodImpl(MethodImplOptions.Synchronized)]
get { return bIsReceivingHeartbeat; }
[MethodImpl(MethodImplOptions.Synchronized)]
set { bIsReceivingHeartbeat = value; }
}
And in the calling code: 并在调用代码中:
if (!IsReceivingHeartbeat) ....
I am writing from Java background but the situation most likely similar 我是从Java背景撰写的,但情况很可能类似
(Looks like you also posted this code in refactormycode.com.) (看起来您也将此代码发布在了refactormycode.com中。)
Anyway, instead of the loop with a sleep delay, I recommend using an Event object that pulsed by the code that sets IsReceivingHeartbeat. 无论如何,我建议您使用一个由设置IsReceivingHeartbeat的代码产生脉冲的Event对象,而不是使用具有睡眠延迟的循环。 See the ManualResetEvent and AutoResetEvent classes in MSDN.
请参阅MSDN中的ManualResetEvent和AutoResetEvent类。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.