i have a simple windows service which runs and starts a thread which listen/receive heartbeat via 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.
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.
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.
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 :)
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. 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.
Try declaring the variables volatile
or use a property and make the getter and setter synchronized:
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
(Looks like you also posted this code in 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. See the ManualResetEvent and AutoResetEvent classes in MSDN.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.