I am reading data through serial port which is working correctly. Following is my code in short
public Form1()
{
InitializeComponent();
//Background worker
m_oWorker = new BackgroundWorker();
m_oWorker.DoWork += new DoWorkEventHandler(m_oWorker_DoWork);
m_oWorker.ProgressChanged += new ProgressChangedEventHandler(m_oWorker_ProgressChanged);
m_oWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(m_oWorker_RunWorkerCompleted);
m_oWorker.WorkerReportsProgress = true;
m_oWorker.WorkerSupportsCancellation = true;
connectComPort.DataReceived += new SerialDataReceivedEventHandler(receiveData);
enableDisable();
}
void m_oWorker_DoWork(object sender, DoWorkEventArgs e)
{
backProcess();
m_oWorker.ReportProgress(100);
}
private void backProcess()
{
//do some work
Thread.Sleep(10000);
if(check if 2000 bytes received)
{
//do some work
}
}
backProcess() is running on background worker and I have a global queue in which I insert bytes received from serial port and I check this queue in if loop.
My problem is that when 2000 bytes are send from other end to pc I receive less than 1000 bytes till after thread.sleep statement but if I set a breakpoint at thread.sleep step I receive complete 2000 bytes. So does thread.sleep(background thread) blocks data receive event handler also? How can I avoid this problem?
Some things don't get quite clear from your question, but I think your design is flawed.
You don't need a background worker at all and you don't need to sleep some thread.
The best way to handle serial input is to use the already asynchronous DataReceived event of the SerialPort class, which is called whenever there's data to be read (you're already doing this, as far as I can tell from your latest edit).
You can then read the existing data, append it to a StringBuilder (or fill a list of up to 2000 bytes) and launch whatever you want to do from there.
Pseudo-Code example would be:
DataReceived event
1. Read data (using `SerialPort.ReadExisting`)
2. Append Data to buffer, increase total number of bytes read
3. If number of bytes >= 2000: Spawn new thread to handle the data
BackgroundWorker is NOT the right tool for this, by the way! If handling the 2000 bytes is fast enough, you don't even need to spawn a new thread at all.
Related
I'm new to multi-threading and I'm to understand how the AutoResetEvent works.
I'm trying to implement an optimization process where I'm sending data between two different softwares and I'm using two threads: the Main thread where I'm modifying and sending information and a Receiving Thread, always running in the background, waiting to catch the message with the results from the Sent Info. To implement that, after a message is sent, I want the main thread to wait until the receiver thread receives back the result and triggers the event that allows the main thread to continue where it left off.
Here is a simplified version of my code:
// Thread 1 - MAIN
static AutoResetEvent waitHandle = new AutoResetEvent(false);
void foo()
{
for (int i = 0; i < 5; i++)
{
// ... Modify sendInfo data
// Send data to other software
SendData(sendInfo);
// Wait for other software to process data and send back the result
waitHandle.WaitOne();
// Print Result
print(receivedData);
// Reset AutoResetEvent
waitHandle.Reset();
}
}
/////////////////////////////
// Thread 2 - Receiver thread (running in the background)
private event EventHandler MessageReceived;
// ... Code for triggerring MessageReceived event each time a message is received
private static void OnMessageReceived(object sender, EventArgs e)
{
waitHandle.Set();
}
My question is:
Can you repeatedly use an AutoResetEvent in a loop like this? Am I using it correctly?
I'm pretty sure my send/receive loop is working properly, with the MessageReceived event succesfully triggered shortly after the sent message. But while my code works fine for a single iteration, it gets stuck on multiple iterations and I'm not sure why. Any suggestions?
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.
I am reading data from a Serial Port in C# as follows:
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
If the function DataReceivedHandler is computationally intensive, is there a way to make sure that when the next data is received it doesn't wait for the previous function to complete, rather it starts another instances of DataReceivedHandler with the new data?
Hmm, I don't think that answer from Gh0st22 is concurrently sound. First off, the DataReceivedHandler is already called from a thread pool internal to the serial port class. Second, I see no locking implemented or mentioned. The serial buffer is going to be a nightmare to handle so let's step back a bit.
Are you actually observing the problem that you are afraid will occur? See this great response that I have referenced many times:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/e36193cd-a708-42b3-86b7-adff82b19e5e/how-does-serialport-handle-datareceived?forum=netfxbcl#298028ff-2b76-4685-947c-f68291882b09
If you absolutely must spin up another thread, consider reading in the available serial data and passing it in as an argument. Otherwise you are just making a huge mess for yourself and any future maintainer on the project.
You can achieve this by using Threading (add using System.Threading;)
public static void main(string[] args)
{
SerialPort mySerialPort = new SerialPort();
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
}
public static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
Thread thread = new Thread(thisClass.Worker);
thread.Start(sender, e);
}
public static void Worker(object sender, object ev)
{
SerialDataReceivedEventArgs e = (SerialDataReceivedEventArgs) ev;
// Put your code here
}
Advantages:
When this method is called while work is being done, it will be allowed to finish
Drawbacks:
The program will continue running, even after its closed, until all threads are finished
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.
I know SerialPort communication in .NET is designed to send the DataReceived event to the receiver when data is available and reach the threshhold.
Can we not use that DataReceived event and start a thread in the receiver side to freqenutly call one of those ReadXXX methods to get data?
What will happen if receiver is much slower than the sender? The SerialPort buffer will overflow (data lost)?
There's little point in doing this, just start the reader thread yourself after you open the port and don't bother with DataReceived. Doing it your way is difficult, tough to cleanly unsubscribe from the DataReceived event after you started the thread, especially at the very moment data is being received. You can't afford to have them both.
That works, in fact it's one of the ways I used in my question Constantly reading from a serial port with a background thread.
For your scenario you could listen to the DataReceived event, then start a thread that calls ReadExisting on the port to get all currently available bytes. You can also check how many bytes are waiting in the receive buffer by looking at the SerialPort.BytesToRead property.
As for your receive buffer overflowing, a) it's big enough (you can check with the SerialPort.ReadBufferSize property) and b) this isn't 1982, so CPUs are fast enough to process data from the port so that it doesn't have time to fill up (certainly much faster than the serial data rate).
The function of the thread that read serial port can be as this:
private void ThreadRx()
{
while (true)
{
try
{
if (this._serialPort.IsOpen == true)
{
int count = this._serialPort.BytesToRead;
if (count > 0)
{
byte[] Buffer = new Byte[count];
this._serialPort.Read(Buffer, 0, count);
//To do: Call your reception event (sending the buffer)
}
else
{
Thread.Sleep(50);
}
}
else
{
Thread.Sleep(200);
}
}
catch (ThreadAbortException ex)
{
//this exception is invoked calling the Abort method of the thread to finish the thread
break;//exit from while
}
catch (Exception ex)
{
//To do:call your error event
}
}
}
Do not worry about the input buffer, because the thread can be read much faster than the baud rate of serial port communication, you can even use this same code to read a tcp/ip socket.