I am facing a problem that a thread in my application runs into a deadlock when I want to close the serial port of a gsm terminal. This problem is well known here and here but all advices in these threads didn't help me.
/// <summary>
/// Closes the COM port, prevents reading and writing
/// </summary>
public void Stop()
{
Debug.WriteLine("stop called");
var block = true;
var bgw = new BackgroundWorker
{
WorkerReportsProgress = false,
WorkerSupportsCancellation = false,
};
bgw.DoWork += (s, e) =>
{
if (!CanAccessPort())
return;
try
{
_serialPort.DataReceived -= Read;
GC.ReRegisterForFinalize(_serialPort.BaseStream);
_serialPort.Close();
_isOpen = false;
}
catch (Exception ex)
{
throw new Exception(PORTERROR, ex);
}
};
bgw.RunWorkerCompleted += (s, e) =>
{
Debug.WriteLine("block is set to false =)");
block = false;
};
bgw.RunWorkerAsync();
while (block)
Thread.Sleep(250);
}
The code above runs forever when _serialPort.Close() is executed. As a recommended advice I read about running the close operation in a separate thread. I tried with BackgroundWorker and Thread classes but nothing did work. Using AutoResetEvent as suggested in another thread did not work either. Before closing the port I am sending some commands to it and receive several results but it won't close. When I run a simple command line program that starts the port, reads data and tries to close it, everything works and even without threads.
What could cause the deadlock? I am not doing any GUI related stuff as mentioned in almost all other answers.
DataReceived event handler code here:
/// <summary>
/// Reads input from the COM interface and invokes the corresponding event depending on the input
/// </summary>
private void Read(object sender, SerialDataReceivedEventArgs e)
{
var buffer = new char[1024];
var counter = 0;
_keepRunning = true;
if (_timeout == null)
{
// timeout must be at least 3 seconds because when sending a sms to the terminal the receive notification (+CSDI) can be lost with less timeout
_timeout = new Timer(3000);
_timeout.Elapsed += (s, ev) =>
{
_keepRunning = false;
_timeout.Stop();
};
}
_timeout.Start();
// cancel condition: no more new data for 3 seconds or "OK"/"ERROR" found within the result
while (_keepRunning)
{
var toRead = _serialPort.BytesToRead;
if (toRead == 0)
{
Thread.Sleep(100);
continue;
}
_timeout.Stop();
_timeout.Start();
counter += _serialPort.Read(buffer, counter, toRead);
// ok or error found in result string
var tmp = new string(buffer).Replace("\0", "").Trim();
if (tmp.EndsWith("OK") || tmp.EndsWith("ERROR"))
{
_timeout.Stop();
_keepRunning = false;
}
}
// remove empty array slots from the back
var nullTerminalCounter = 0;
for (var i = buffer.Length - 1; i != 0; i--)
{
if (buffer[i] == '\0')
{
nullTerminalCounter++;
continue;
}
break;
}
Array.Resize(ref buffer, buffer.Length - nullTerminalCounter);
var str = new String(buffer).Trim();
// result must be something different than incoming messages (+CMTI: \"MT\", 25)
if (!((str.StartsWith("+CMTI") || str.StartsWith("+CSDI")) && str.Length < 20))
{
// when an incoming message is received, it does not belong to the command issued, so result has not yet arrived, hence port is still blocked!
_isBlocked = false;
Debug.WriteLine("port is unblocked");
}
var args = new CommandReturnValueReceivedEventArgs
{
ResultString = str
};
OnCommandReturnValueReceived(this, args);
}
if (toRead == 0)
{
Thread.Sleep(100);
continue;
}
This code is the basic source of the deadlock. The rule for SerialPort.Close() is that it can only close the serial port when none of the event handlers for SerialPort are active. Problem is, your DataReceived event handler is almost always active, waiting for data. This was not the intended use for the event. You are supposed to read whatever is available from the serial port, typically appending bytes to a buffer and get out. The event fires again when more bytes are available.
while (_keepRunning)
Looks like you discovered this problem and tried to fix it with the Timer. That doesn't work either, in a very ratty way that's very difficult to debug. A bool variable is not a proper synchronization primitive, like ManualResetEvent. The while() loop will not see the _keepRunning variable turn to false when you target x86 and run the Release build of your program. Which enables the jitter optimizer, it is apt to store the variable in a cpu register. Declaring the variable volatile is required to suppress that optimization.
I suspect, but can't guarantee, that using volatile will solve your problem. And you probably want to set _keepRunning to false before calling Close() so you don't get the timeout delay.
A more structural fix is however indicated. Rewrite the DataReceived event handler so it never loops waiting for data. Given that this appears to be code to talk to a modem, a simple _serialPort.ReadLine() call should be all that's required.
The issues I had went away if I ensured that Open and Close never were called at the same time by any thread. I did this by using a lock.
The essence is the following.
lock(_port)
_port.Open(.....);
...
lock(_port)
_port.Close(.....);
Related
I have a timer event that executes the following code. I'm trying to read from a TCP connection for a specific string, but it doesn't seem like the buffer gets updated on each passing timer tick event. The source that I'm getting this data from will send 4 different types of strings in a byte array depending on the current state of the system. They are sent to me on a continuous basis. What appears to be happening is that I read just once and then not again for some reason. I've verified that the source I'm receiving data from is indeed sending me different messages, but I don't seem to be able to "read" them. Just the first time only apparently. I tried using the Array.Clear() method, but I still only seem to get one buffer of data and not something that is continuously updating itself. The point of this timer event is to continuously update a C# Windows Form app to alert someone of a fault. I created the "PartnerClient TCPClient at the top of my program.
I'm hopeful that someone has some advice. Perhaps I need an EndRead, but I have tried this approach. Any advice would help
public void FaultDataTimer_Tick(object sender, EventArgs e)
{
byte[] mRx = new byte[9];
byte[] statusBytes = new byte[9];
string strRecv;
string[] values = { "ULI_Fault", "DynoFault", "ULI_AOkay", "DynoAOkay" };
if (PartnerClient.Connected == true)
{
try
{
PartnerClient.GetStream().BeginRead(mRx, 0, mRx.Length, null, PartnerClient);
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
for (int i = 0; i < 9; i++)
{
statusBytes[i] = mRx[i];
}
strRecv = Encoding.ASCII.GetString(statusBytes);
if (values.Any(strRecv.Contains) || values.Any(strRecv.Contains))
{
if (strRecv == "ULI_Fault")
{
uliPanel.BackColor = Color.Red;
}
else if (strRecv == "DynoFault")
{
dynoPanel.BackColor = Color.Red;
}
else if (strRecv == "ULI_AOkay")
{
uliPanel.BackColor = greenColor;
}
else if (strRecv == "DynoAOkay")
{
dynoPanel.BackColor = greenColor;
}
}
}
Array.Clear(mRx, 0, mRx.Length);
}
I use this code for receiving scanlines:
StateObject stateobj = (StateObject)ar.AsyncState;
stateobj.workSocket.BeginReceive(new System.AsyncCallback(VideoReceive), stateobj);
UdpClient client = stateobj.workSocket;
IPEndPoint ipendp = new IPEndPoint(IPAddress.Any, 0);
byte[] data = client.EndReceive(ar, ref ipendp);
BinaryReader inputStream = new BinaryReader(new MemoryStream(data));
inputStream.BaseStream.Position = 0;
int currentPart = inputStream.ReadInt32();
if (currentPart == part)
{
int a = 0;
int colum = inputStream.ReadInt32();
for (; a < packets.GetLength(1); a++)
{
packets[colum, a, 2] = inputStream.ReadByte();
packets[colum, a, 1] = inputStream.ReadByte();
packets[colum, a, 0] = inputStream.ReadByte();
}
receiverCheck++;
}
else if (currentPart != part)
{
part++;
mask2.Data = packets;
pictureBox1.BeginInvoke(new MethodInvoker(() => { pictureBox1.Image = mask2.ToBitmap(); }));
int colum = inputStream.ReadInt32();
for (int a = 0; a < packets.GetLength(1); a++)
{
packets[colum, a, 2] = inputStream.ReadByte();
packets[colum, a, 1] = inputStream.ReadByte();
packets[colum, a, 0] = inputStream.ReadByte();
}
}
After all scanlines have been received the image displayed in pictureBox.
This should work, but have a lot lost packets even on localhost (only ~ 95 of 480), so I have striped image. I found a similar problem here.
Answer:
private void OnReceive(object sender, SocketAsyncEventArgs e)
{
TOP:
if (e != null)
{
int length = e.BytesTransferred;
if (length > 0)
{
FireBytesReceivedFrom(Datagram, length, (IPEndPoint)e.RemoteEndPoint);
}
e.Dispose(); // could possibly reuse the args?
}
Socket s = Socket;
if (s != null && RemoteEndPoint != null)
{
e = new SocketAsyncEventArgs();
try
{
e.RemoteEndPoint = RemoteEndPoint;
e.SetBuffer(Datagram, 0, Datagram.Length); // don't allocate a new buffer every time
e.Completed += OnReceive;
// this uses the fast IO completion port stuff made available in .NET 3.5; it's supposedly better than the socket selector or the old Begin/End methods
if (!s.ReceiveFromAsync(e)) // returns synchronously if data is already there
goto TOP; // using GOTO to avoid overflowing the stack
}
catch (ObjectDisposedException)
{
// this is expected after a disconnect
e.Dispose();
Logger.Info("UDP Client Receive was disconnected.");
}
catch (Exception ex)
{
Logger.Error("Unexpected UDP Client Receive disconnect.", ex);
}
}
}
Answer has method FireBytesReceivedFrom(), but I can't find it. How can I use this code? And does this code help?
UDP doesn't guarantee that all packets will be received, it that they will arrive in any particular order. So even if you get this "working" be aware that it could (will probably) fail at some point.
When you call BeginReceive, you are starting an sync read. When data arrives, your event handler will be called, and it is then that you need to call EndReceive. Currently you are calling EndReceive immediately, which is probably why things are going wrong.
Some other notes:
I'd suggest that you don't try to be clever and re-use the buffer, as that could result in you losing data by overwriting data while you are trying to read it. Start off simple and add optimizations like this after you have it working well.
Also, the goto could be causing havoc. You seem to be trying to use it to retry, but this code is running IN the data received event handler. Event handlers should handle the event in the most lightweight way possible and then return, not start looping... especially as the loop here could cause a re-entrant call to the same event handler.
With async comms, you should start a read and exit. When you eventually receive the data (your event handler is called), grab it and start a new async read. Anything more complex than that is likely to cause problems.
The Fire... method you are missing probably just raises (fires) an event to tell clients that the data has arrived. this is the place where you should be grabbing the received data and doing something with it.
If you are using an example to build this code then I suggest you look for a better example. (in any case I would always recommend trying to find 3 examples so you can compare the implementations, as you will usually learn a lot more about something this way)
I have one main form class and another class. In the second class, I have a thread loop:
public void StartListening()
{
listening = true;
listener = new Thread(new ThreadStart(DoListening));
listener.Start();
}
// Listening for udp datagrams thread loop
/*=====================================================*/
private void DoListening()
{
while (listening)
{
IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, port);
byte[] content = udpClient.Receive(ref remoteIPEndPoint);
if (content.Length > 0)
{
string message = Encoding.ASCII.GetString(content);
delegMessage(message);
}
}
}
// Stop listening for udp datagrams
/*=====================================================*/
public void StopListening()
{
lock (locker)
{
listening = false;
}
}
In main form class, I start this listening in class constructor
udp.StartListening();
And than, in this main form class, I have key hook event, too. In this event, I wan to stop thread running in the second class.
private void hook_KeyPressed(int key)
{
if (key == (int)Keys.LMenu)
altPressed = true;
if (key == (int)Keys.F4 && altPressed == true)
udp.StopListening();
}
Unfortunetely, the thread is still running.
Do you have some ideas about this??
Thank you very much.
Your thread is blocking at the byte[] content = udpClient.Receive(ref remoteIPEndPoint); line. The Receive method blocks until something is received.
You should use the asynchronous version (BeginReceive) instead.
Also, another flaw in your code - you check for the stopping condition without any synchronization. Here:
private void DoListening()
{
while (listening){ //this condition could stuck forever in 'false'
}
Actually, without a memory barrier, there is no guarantee, that a thread, that is running DoListening will ever see the change to listening var from other thread. You should at least use locking here (which provides memory barrier)
As #igelineau pointed out - your code is blocking on the receive call. If you don;t want to go down the async route (which I'd recommend) just send something to the udp port in your stop listening method.
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.
p.s: 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.
I'm having trouble with a processing thread in C#. Basically the thread manages chat windows when new messages arrive or are sent and unfortunately I'm having different situations occur based on the running environment.
When running a Debug build (either with or without a debugger), or a Release build under a debugger, the Process() function operates correctly, shows windows and receives messages fine.
However, when running a Release build without a debugger, the Application.Run() call seems to stop the processing of the main Process() thread (notice that this call happens under a sub-thread of the processing thread) and so no more processing occurs.
Through the use of the MessageBox.Show() call I have determined that Application.Run() is the last call to be made before no more message boxes are shown (and they should be as it shows how many messages are received each time the while loop runs).
Does anyone know why the Application.Run() call is behaving differently under this situation?
/// <summary>
/// Processes the IM message queue, managing the chat windows and messages.
/// </summary>
private void Process()
{
try
{
MessageBox.Show("MessageQueue process has started!");
while (this.m_Running)
{
List<Message> messages = null;
lock (this.m_Lock)
{
messages = new List<Message>(this.m_Messages);
MessageBox.Show("MessageQueue received " + this.m_Messages.Count + " messages on this spin.");
this.m_Messages.Clear();
}
// Process all the messages
foreach (Message m in messages)
{
Contact c = m.Contact;
if (!this.m_Windows.Keys.Contains(c.ID) || this.m_Windows[c.ID] == null)
{
MessageBox.Show("MessageQueue is creating a new window.");
bool complete = false;
Thread t = new Thread(() =>
{
try
{
ChatWindow w = new ChatWindow(this, c, new Contact(this.m_Client.JID, null));
w.Load += (sender, e) =>
{
if (m.IsTo)
w.AppendSentMessage(m.To, m.Data);
else if (m.IsFrom)
w.AppendRecievedMessage(m.From, m.Data);
w.UpdateStatus(c);
};
w.FormClosed += (sender, e) =>
{
this.m_Windows[c.ID] = null;
};
c.StatusUpdated += (sender, e) =>
{
RoketPack.Manager.VoidLambda lambda = () =>
{
w.UpdateStatus(c);
};
if (w.InvokeRequired)
w.Invoke(lambda);
else
lambda();
};
MessageBox.Show("MessageQueue is now showing the new window.");
w.Show();
if (!this.m_Windows.Keys.Contains(c.ID))
this.m_Windows.Add(c.ID, w);
else
this.m_Windows[c.ID] = w;
complete = true;
MessageBox.Show("MessageQueue is now running the new window.");
Application.Run(w);
MessageBox.Show("MessageQueue is now closing the window.");
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
complete = true;
}
});
t.Name = "IM Chat Window - " + c.ID;
t.IsBackground = true;
t.Start();
// We have to wait until the form has been added to the dictionary.
while (!complete) ;
}
else
{
RoketPack.Manager.VoidLambda lambda = () =>
{
if (m.IsTo)
this.m_Windows[c.ID].AppendSentMessage(m.To, m.Data);
else if (m.IsFrom)
this.m_Windows[c.ID].AppendRecievedMessage(m.From, m.Data);
MessageBox.Show("MessageQueue appended the message to the chat window.");
};
MessageBox.Show("MessageQueue received a message and is now forwarding it onto the chat window.");
if (this.m_Windows[c.ID].InvokeRequired)
this.m_Windows[c.ID].Invoke(lambda);
else
lambda();
}
}
// Sleep for 10 milliseconds.
Thread.Sleep(10);
}
}
finally
{
MessageBox.Show("MessageQueue process has terminated!");
}
}
Aside from what leppie wrote, this looks like a bad starting point:
while (!complete);
I don't know exactly what guarantees there are around hoisted variables and visibility, but tight-looping is almost always a bad idea.
It would generally be better to use a Wait/Notify approach or an Auto/ManualResetEvent.
Do you realize Application.Run does not return until your application closes?
It also seems you are calling Application.Run from a child thread.