C# multiple COM port synchronization - c#

I am porting an existing app from Borland C++ to .NET. Application handles 4 COM Ports simultaneously, i need to synchronize them, so that whilst one port is receiving data, the other three would block until one reads all the data in the receive buffer.
Requirements are, that new version works exactly in the same way as the previous one, so i need to find a way how to synchronize those 4 ports.
P.S.
I have got 4 instances of SerialPort class.
Below is a handler for receiving data over the COM port.
private void SerialPort_DataReceived( object sender, SerialDataReceivedEventArgs e )
{
SerialPort rThis = (SerialPort)sender;
string existingData = rThis.ReadExisting();
int NumReceived = existingData.Length;
if (NumReceived > 0)
{
char[] ReceivedByte = existingData.ToCharArray();
// if RX bytes cannot be processed
if (!rThis.ProcessReceivedBytes(ReceivedByte, NumReceived))
{
rThis.ReportThreadError(ThreadId.TI_READ, 0x07FFFFF);
}
}
}

Best thing is you have only one thread interacting with the ports, because this way you can't interact with the other ports while the thread is busy. This is exactly what you want, forget about multi-threading here.
Then, you should separate that low-level I/O thread from the GUI thread. So you'll end up with two threads that comunicate with one another over a well-defined API.
The low-level I/O thread requires a way of polling the serial ports without blocking, something like this:
while(polling) // GUI thread may interrupt polling on user request
{
foreach(SerialPort port in serialports)
{
if(port.HasDataToRead) // this is the polling you really need
{
// read data from port and handle it accordingly
}
}
// ... suspend thread now and then to prevent loop from consuming CPU time
}
The HasDataToRead should be implemented in the event handler, meaning:
catch in the event handler the event data is available and signal it with HasDataToRead inside the SerialPort class;
don't read the actual data in the event handler, event handlers often run on the GUI thread, you don't want to lock up the GUI;
at the end of the read method clear the HasDataToRead flag.
The cycle above really is a dispatcher, while the events are only used to orchestrate the flags inside the SerialPort instances.
Pay attention to the HasDataToRead flag, you'll have to lock it to avoid race conditions:
lock(HasDataToRead)
{
// access HasDataToRead
}

Related

What happens if event occurs again when the first is not finished handling

My Question is about the DataReceived event from an System.IO.SerialPort. I have a method which gets called when that event occurs. I read the Data with myPort.ReadExisting, process it and save it. If I get a specific character the data up to that point is interpreted as command and another event is triggered.
My question is, what happens if I'm in the middle of processing the received Data and new data comes? Is the new instances of the method waiting for the old to finish? If not it could result in a conflict because both instances of that method use the same variables. Am I wrong in the concept of event handling or is there an elegant way to deal with that.
My code is running fine and my results are as expected, but my data processing is not that sophisticated. I just want to understand this issue und avoid getting problems in the future.
My Code example would be this:
private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort port = (SerialPort)sender;
int index = m_ports.FindIndex(p => p.PortName == port.PortName);
string tmpData;
m_currentData[index] += tmpData = port.ReadExisting();
Console.WriteLine(tmpData);
string currentData = m_currentData[index];
string currentOrder = "";
while (currentData.Contains(orderEndChar))
{
int endCharLocation = currentData.IndexOf(orderEndChar);
currentOrder = currentData.Substring(0, endCharLocation);
currentData = currentData.Substring(endCharLocation + 1);
orderEvent.gotOrder(currentOrder);
//orderEvent.gotOrder(new EventArgs());
}
m_currentData[index] = currentData;
}
The lists are because I want it to work with multiple Ports from where I can get commands.
SerialPort.DataReceived is invoked on secondary thread.
Read here:
https://msdn.microsoft.com/fi-fi/library/system.io.ports.serialport.datareceived(v=vs.110).aspx
So if you have many SerialPort instances listening, it may happen that there will be more that one Port_DataReceived methods running at the same time. But do not be afraid of local variables, as they live only in specific method call. Therefore 3 different threads running the same method will initiate 3 different local variables, even if their name is the same. But be careful with global variables.
Since Port_DataReceived is synchronous, the next event invocation on the same SerialPort object will wait so these invocations are performed one by one.
So, if you suspect that your producer might run faster than your consumer, you should decouple the two through the use of a queue.
All your producer has to do is push the data it receives into a (thread-safe) queue... a quick operation that will not overrun.
All the consumer has to do is read from the queue, at it's own speed.
TPL Dataflow offers the BufferBlock<T> class which might serve as a handy queue for such a producer/consumer relationship.
You might choose to dig a bit deeper into dataflow. It's perfect for producer/consumer stuff in an async world.
Start here: https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-write-messages-to-and-read-messages-from-a-dataflow-block

C#, Execute Event Handler in separate thread

I'm currently working on a program's subsystem that requires writing data to disk. I've implemented this as a multithreaded Producer-Consumer model that generates packets of data in one thread, puts them in a queue and writes them to disk in another thread.
The program has to use minimal CPU resources, so to avoid the write thread idling while it is waiting for a packet of data to arrive, I extended the ConcurrentQueue class to trigger an Event when a packet has been added to the queue, so that the write function is only active when there is data available. Here's the generate function:
while (writeData)
{
for (int i = 0; i < packetLength; i++)
{
packet.data[i] = genData();
}
packet.num++;
// send packet to queue to be written
// this automatically triggers an Event
queue.Enqueue(packet);
}
My problem is that I haven't been able to figure out how to assign the Event Handler (ie: the write operation) to a seperate thread - as far as I'm aware, Event Handlers in C# are run on the same thread that triggered the event.
I've thought about using the ThreadPool, but I'm unsure as to whether the packets in the queue would be written sequentially or in parallel. Writing packets in parallel would not work in this context, as they are all being written to the same file and have to be written in the order they arrive in. This is what I have so far:
private void writeEventCatch(object sender, EventArgs e)
{
// catch event and queue a write operation
ThreadPool.QueueUserWorkItem(writeToDisk);
}
private void writeToDisk(Object stateInfo)
{
// this is a struct representing the packet
nonCompBinData_P packet;
while (queue.TryDequeue(out packet))
{
// write packet to stream
serialiser.Serialize(fileStream, packet);
packetsWritten++;
}
}
while (queue.TryDequeue(out packet)) will quit as long as there are no packets to dequeue. what you need to do is start single thread for writing operation deque work items and write data to disk. items will be dequeued one by one and in order they arrive.

How to keep a thread alive in C#

I have a windows service that is designed to handle incoming data, process it, and alert users if necessary. One thing that I am having trouble figuring out is how to keep a thread alive.
I have a few classes that share a ConcurrentBag of Device objects. The DeviceManager class is tasked with populating this collection and updating the device objects if a parameter about a device changes in the database. So for example, in the database someone updates device 23 to have a normal high of 50F. The DeviceManager would update the appropriate device in memory to have this new value.
Oracle provides an event handler to be notified when a table changes (docs here). I want to attach an event handler so I can be notified when to update my devices in memory. The problem is, how can I create a thread for my DeviceManager to work in and for it to just idle in the thread until the event occurs and is handled there? I would like to have the event fire and be handled in this thread instead of the main one.
You can create a separate worker thread when your service starts up. The worker thread will connect to the database and listen for change notifications, and update your ConcurrentBag accordingly. When the service is shut down, you can gracefully terminate the thread.
MSDN has an example that I think will help you: How to: Create and Terminate Threads
There are a large number of synchronization techniques available in .NET, and to discuss the entire scope would be too broad to address here. However, you should look at the Monitor class, with its Wait() and Pulse() methods.
For example:
private readonly object _lockObj = new object();
public void StartThread()
{
new Thread(ThreadProc).Start();
}
public void SignalThread()
{
lock (_lockObj)
{
// Initialize some data that the thread will use here...
// Then signal the thread
Monitor.Pulse(_lockObj);
}
}
private void ThreadProc()
{
lock (_lockObj)
{
// Wait for the signal
Monitor.Wait(_lockObj);
// Here, use data initialized by the other thread
}
}
Of course you can put the thread's locking/waiting code in a loop if you need for the thread to repeat the operation.
It looks like there's no shortage of other questions involving the Monitor class on SO:
https://stackoverflow.com/search?q=%5Bc%23%5D+monitor+pulse+wait
And of course, the documentation on MSDN has other examples as well.

How do I transmit over the serial port asynchronously in .NET?

I am writing a program to simulate a device that transmits data over the serial port. To do this, I created a System.IO.Ports.SerialPort object in my form, and a System.Windows.Forms.Timer to do the transmitting at a given frequency. Everything works fine except that as the frequency approaches the limit of the serial port speed, it starts to lock up the UI and eventually becomes unresponsive when the data is being sent for transmission faster than the port data speed. My code is:
private void OnSendTimerTick(object sender, EventArgs e)
{
StringBuilder outputString = new StringBuilder("$", 51);
//code to build the first output string
SendingPort.WriteLine(outputString.ToString());
outputString = new StringBuilder("$", 44);
//code to build the second output string
SendingPort.WriteLine(outputString.ToString());
if (SendingPort.BytesToWrite > 100)
{
OnStartStopClicked(sender, e);
MessageBox.Show("Warning: Sending buffer is overflowing!");
}
}
I was expecting the WriteLine function to be asynchronous - return immediately while the port transmits in the background. Instead, it seems that the OnSendTimerTick function is properly threaded, but WriteLine seems to be running in the UI thread.
How can I get the serial port to behave in this way? Creating the SerialPort object in the timer seems like a bad idea, because then I'd have to open and close it on each timer tick.
It is only partly asynchronous, it will immediately return but only as long as the bytes you write will fit in the serial port driver's transmit buffer. That's going to come to a screeching stop when you flood the port with too much data, faster than it can transmit. You can make it truly asynchronous by using the SerialPort.BaseStream.BeginWrite() method. That doesn't make it any faster but moves the bottleneck somewhere else, possibly away from the UI.
If you're using System.Windows.Forms.Timer, the timer event handler is being executed on the UI thread. Same is true if you're using System.Timers.Timer when the SynchronizingObject is set to the form. If the serial port buffer fills up, the thread has to wait until it has enough space to hold the new data that you want to send.
I would suggest that you use a System.Threading.Timer to do this. The timer callback is called on a pool thread, meaning that the UI thread won't lock up if the WriteLine has to wait. If you do this, then you have to make sure that there is only one threading executing the timer callback at any time. Otherwise you can get data out of order. The best way to do that would be to make the timer a one-shot and re-initialize it at the end of every callback:
const int TimerFrequency = 50; // or whatever
System.Threading.Timer timer;
void InitTimer()
{
timer = new System.Threading.Timer(TimerCallback, null, TimerFrequency, Timeout.Infinite);
}
void TimerCallback(object state)
{
// do your stuff here
// Now reset the timer
timer.Change(TimerFrequency, Timeout.Infinite);
}
Passing a valid of Timeout.Infinite as the period parameter prevents the timer from being a periodic timer. Instead, it fires just once. The Timer.Change re-initializes the timer after each send.
A possibly better way to handle this is to eliminate the timer altogether by setting the WriteBufferSize to a sufficiently large value. Then your program can just dump all of its data into the buffer and let the SerialPort instance worry about dribbling it out across the wire. This assumes, of course, that you can create a buffer large enough to hold whatever your program is trying to send.
This could be resolved(slowness of the UI) if you created a Queue of strings to be written and had a background thread that wrote to the serial port from the queue. If you take that approach be careful of the size of the queue.
edit: For some reason I can't use Add Comment, so I'll just edit this. The documentation for BeginWrite has this statement "The default implementation of BeginWrite on a stream calls the Write method synchronously, which means that Write might block on some streams." It then goes on to exclude File and Network streams, but not SerialPort. I guess you can try it and see.

C#: Handling terminate signal in TCP handler thread?

I am using the TcpClient class in C#.
Each time there is a new tcp connection request, the usual practice is to create a new thread to handle it. And it should be possible for the main thread to terminate these handler threads anytime.
My solution for each of these handler thread is as follows:
1 Check NetworkStream's DataAvailable method
1.1 If new data available then read and process new data
1.2 If end of stream then self terminate
2 Check for terminate signal from main thread
2.1 If terminate signal activated then self terminate
3 Goto 1.
The problem with this polling approach is that all of these handler threads will be taking up significant processor resources and especially so if there is a huge number of these threads. This makes it highly inefficient.
Is there a better way of doing this?
See Asynchronous Server Socket Example to learn how to do this the ".NET way", without creating new threads for each request.
Believe it or not that 1000 tick sleep will really keep things running smooth.
private readonly Queue<Socket> sockets = new Queue<Socket>();
private readonly object locker = new object();
private readonly TimeSpan sleepTimeSpan = new TimeSpan(1000);
private volatile Boolean terminate;
private void HandleRequests()
{
Socket socket = null;
while (!terminate)
{
lock (locker)
{
socket = null;
if (sockets.Count > 0)
{
socket = sockets.Dequeue();
}
}
if (socket != null)
{
// process
}
Thread.Sleep(sleepTimeSpan);
}
}
I remember working on a similar kind of Windows Service. It was a NTRIP Server that can take around 1000 TCP connections and route the data to a NTRIP Caster.
If you have a dedicated server for this application then it will not be a problem unless you add more code to each thread (File IO, Database etc - although in my case I also had Database processing to log the in/out for each connection).
The things to watch out for:
Bandwidth when the threads goes up to 600 or so. You will start seeing disconnections when the TCP Buffer window is choked for some reason or the available bandwidth falls short
The operating system on which you are running this application might have some restrictions, which can cause disconnections
The above might not be applicable in your case but I just wanted it put it here because I faced then during development.
You're right that you do not want all of your threads "busy waiting" (i.e. running a small loop over and over). You either want them blocking, or you want to use asynchronous I/O.
As John Saunders mentioned, asynchronous I/O is the "right way" to do this, since it can scale up to hundreds of connections. Basically, you call BeginRead() and pass it a callback function. BeginRead() returns immediately, and when data arrives, the callback function is invoked on a thread from the thread pool. The callback function processes the data, calls BeginRead() again, and then returns, which releases the thread back into the pool.
However, if you'll only be holding a handful of connections open at a time, it's perfectly fine to create a thread for each connection. Instead of checking the DataAvailable property in a loop, go ahead and call Read(). The thread will block, consuming no CPU, until data is available to read. If the connection is lost, or you close it from another thread, the Read() call will throw an exception, which you can handle by terminating your reader thread.

Categories

Resources