Output individual data from structure based on timer - c#

I'am creating a "man-in-middle" style application that applies a network latency to the transmissions, not for malicious use I should declare.
However I'm having difficulty with the correct output mechanisms on the data structure (LinkedList<string> buffer = new LinkedList<string>();).
What should happen:
Read data into structure from clientA.
if (buffer.First != null && buffer.Last != null)
{
buffer.AddAfter(buffer.Last, ServerRead.ReadLine().ToString());
}
else
buffer.AddFirst(ServerRead.ReadLine().ToString());
Using an individual or overall timer to track when to release the data to ClientB. (adjustable timer to adjust latency)
Timer on item in structure triggers, thus releasing the packet to clientB.
Clean up free data structure node
if (buffer.First != null)
{
clientWrite.WriteLine(buffer.First.Value.ToString());
clientWrite.Flush();
buffer.RemoveFirst();
}
However I have been trying to use the System.Windows.Forms.Timer to create a global timer that triggers a thread which handles the data output to clientB. However I'am finding this technique to be too slow, even when setting the myTimer.Interval = 1; This creates a concurrency problem with when clearing up the list and adding to it, the temporary solution is by locking the resource but I feel this is adding to the slow performance of data output.
Question:
I need some ideas on a solution that can store data into a data structure and apply a timer (like an egg timer effect) on the data stored and when that timer runs out it will be sent on its way to the other clients.
Regards, House.

The linked list will work, and it's unlikely that locking it (if done properly) will cause poor performance. You'd probably be much better off using ConcurrentQueue. It's thread-safe, so you don't have to do any explicit blocking.
I would suggest using System.Threading.Timer rather than the Windows Forms timer. Note, though, that you're still going to be limited to about 15 ms resolution. That is, even with a timer interval of 1, your effective delay times will be in the range of 15 to 25 ms rather than 1 ms. It's just the way the timers are implemented.
Also, since you want to delay each item for a specified period of time (which I assume is constant), you need some notion of "current time." I don't recommend using DateTime.Now or any of its variants, because the time can change. Rather, I use Stopwatch to get an application-specific time.
Also, you'll need some way to keep track of release times for the items. A class to hold the item, and the time it will be sent. Something like:
class BufferItem
{
public string Data { get; private set; }
public TimeSpan ReleaseTime { get; private set; }
public BufferItem(string d, TimeSpan ts)
{
data = d;
ReleaseTime = ts;
}
}
Okay. Let's put it all together.
// the application clock
Stopwatch AppTime = Stopwatch.StartNew();
// Amount of time to delay an item
TimeSpan DelayTime = TimeSpan.FromSeconds(1.0);
ConcurrentQueue<BufferItem> ItemQueue = new ConcurrentQueue<BufferItem>();
// Timer will check items for release every 15 ms.
System.ThreadingTimer ReleaseTimer = new System.Threading.Timer(CheckRelease, null, 15, 15);
Receiving an item:
// When an item is received:
// Compute release time and add item to buffer.
var item = new BufferItem(data, AppTime.Elapsed + DelayTime);
ItemQueue.Add(item);
The timer proc.
void CheckRelease(object state)
{
BufferItem item;
while (ItemQueue.TryPeek(out item) && item.ReleaseTime >= AppTime)
{
if (ItemQueue.TryDequeue(out item))
{
// send the item
}
}
}
That should perform well and you shouldn't have any concurrency issues.
If you don't like that 15 ms timer ticking all the time even when there aren't any items, you could make the timer a one-shot and have the CheckRelease method re-initialize it with the next release time after dequeing items. Of course, you'll also have to make the receive code initialize it the first time, or when there aren't any items in the queue. You'll need a lock to synchronize access to updating the timer.

Related

How can I read a constant stream of data and keep my ListView updated in real time?

I'm Using a Task to start a while loop to run and constantly collect data from from a USB device. The data can come in very fast, multiple messages per millisecond. I want to display the data in real time using a ListView.
The goal is to have two options to display the data. The first way is to display the newest message at the top of the list view. I've tried calling a dispatcher and inserting the data at the beginning of an ObservableCollection. This works fine with a message every 20 ms or so.
Often the data coming in is the same message again and again with a consistent interval. The second way is to have a row in the listview for each unique message. As a new message comes in it either takes the place of the previous similar message or it is inserted into a new position. I accomplished this by inheriting from ObservableCollection and implementing a binarysearch function to get an index and then replace or insert the newest message. This also worked fine at about the same rate.
The problem is Updating the UI can't keep up with reading the data from the USB device when the traffic coming from the USB device is heavy. It worked fine with low volumes of data but I'm stuck trying to make this thing more efficient.
I've tried creating my own methods in my ExtendedObservableCollection. I created some AddRange methods for each scenario and calling OnCollectionChange after all the updates. The performance this way seems to be even worse than it was before which is very confusing to me. This seems like the way to go. I think the issue has something to do with my while loop which is collecting the data and the AddRange method not getting along.
I also tried calling BindingOperations.EnableCollectionSynchronization(MessageList, balanceLock);
with out using the dispatcher and it didn't seem to help much. I put my AddRange methods inside a lock statement.
I also tried running the Batchupdate method in its own while loop running parallel the my loop collecting data it didn't work at all.
This is my loop for reading the messages from the USB device
int interval = 40;
private void BeginReading()
{
do
{
waitHandle.WaitOne(TimeSpan.FromMilliseconds(.5));
if (ReadOk)
{
MessageBuffer.Add(message);
}
if (Stopwatch.ElapsedMilliseconds > interval)
{
BatchUpdate();
MessageBuffer = new List<Message>();
interval += 40;
}
} while (ReceiveReady);
}
This is one of my AddRange Methods in my extended ObservableCollection
public void AddRangeScroll(List<Message> MessageList)
{
if (MessageList == null) throw new ArgumentNullException("List");
foreach (Message message in MessageList)
{
Items.Insert(0, message);
}
OnCollectionChanged(newNotifyCollectionChangedEventArgs
(NotifyCollectionChangedAction.Reset));
}
I'm hoping I'll be able to read the data from the USB device and update the ListView in something that resembles real time.
The messages I'm reading are CAN messages and I'm using the PEAK PCANBasic API to connect to one of their gridconnect USB to CAN devices.
Your approach is absolutely bad. You are blocking threads and keep them busy with useless resources consuming polling. (I don't know why you are making the thread wait. But consider to use a non-blocking wait handle operation like SemaphoreSlim.WaitAsync or similar. Maybe the awaitable Task.Delay is sufficient at this point. No waiting would be the best.)
If you wish to group messages like same type together use a Dictionary<K, V> e.g. Dictionary<string, IEnumerable<string>> where the key is the type of the message and the value a collection of grouped messages. The lookup is very fast and doesn't require any search. For this scenario consider to introduce a type for the key (e.g. an enum) and overwrite GetHash on it to improve performance. If the key is guaranteed to be unique hash tables perform the best.
First option is to use an event driven logic:
public void ReadDataFromUsb()
{
var timer = new System.Timers.Timer(40);
timer.Elapsed += ReadNextDataBlockAsync;
}
// Will be invoked every 40 ms by the timer
public async void ReadNextDataBlockAsync(Object source, ElapsedEventArgs e)
{
await Task.Run(BeginReading);
}
private void BeginReading()
{
// Read from data source
}
Second option is to use yield return and make BeginRead return an IEnumerable. You can then use it like this:
foreach (var message in BeginRead())
{
// Process message
}
Third option is to use Producer Consumer Pattern using a BlockingCollection<T>. It exposes a non-blocking TryTake method to get the items that are ready for consumption.
See Dataflow (Task Parallel Library) to get more solutions how to handle data flow without blocking threads.
Since a 40 ms data refresh rate is very high also consider to show snapshots that are expandable when details are needed by the user.

BlockingCollection that doesn't try again within 10 seconds

I am using a Blockingcollection as a FIFO queue but I am doing a lot of operations on files, where the consumer may easily encounter a file lock, so what I have done is created a simple try catch where the consumer re-queue's itself, but in a long FIFO queue with lots of other Items in the queue this is enough of a pause, but in an empty or very short FIFO queue it means the consumer perpetually hammers the queue with repeating re-occurrences of itself that are probably going to be still file locked.
i.e.
consumer busy -> requeue -> consumer busy -> requeue (ad infinitum)
is there a way to get the BlockingCollection to not attempt to run the new consumer if it is less than 10 seconds old? i.e. potentially get the net one in the queue and carry on and only take the next consumer if it's createdDateTime is null (default for first attempt) or if it is > 10 seconds?
There's nothing built-in to help with that. Store with each work item the DateTime when it was last attempted (could be null if this is the first attempt). Then, in your processing function wait for TimeSpan.FromSeconds(10) - (DateTime.UtcNow - lastAttemptDateTime) seconds before making the next attempt.
Consider switching to a priority queue that stores items in the order of earliest next attempt datetime.
You could keep two blocking collections: the main one and the "delayed" one. One worker thread would only work on the delayed one, readding them to the main collection. The signature of the rejected collection would be something like:
BlockingCollection<Tuple<DateTime, YourObject>>
now... If the time is fixed at 10 seconds, the delayed collection will nearly be DateTime sorted (in case of items added nearly at the same time this could be not-true, but we are speaking of milliseconds difference... not a problem)
public class MainClass
{
// The "main" BlockingCollection
// (the one you are already using)
BlockingCollection<Work> Works = new BlockingCollection<Work>();
// The "delayed" BlockingCollection
BlockingCollection<Tuple<DateTime, Work>> Delayed = new BlockingCollection<Tuple<DateTime, Work>>();
// This is a single worker that will work on the Delayed collection
// in a separate thread
public void DelayedWorker()
{
Tuple<DateTime, Work> tuple;
while (Delayed.TryTake(out tuple, -1))
{
var dt = DateTime.Now;
if (tuple.Item1 > dt)
{
Thread.Sleep(tuple.Item1 - dt);
}
Works.Add(tuple.Item2);
}
}
}

How to process (dynamically added) items at a given time?

I've got a (concurrent) priority queue with a timestamp (in the future) as the key and a function that should be called (/ an item that should be processed) when the time is reached as the value. I don't want to attach a timer to each item, cause there a lots of it. I'd rather go with a scheduler thread/task.
What would be a good strategy to do so?
With a thread running a scheduler... (pseudo-code follows)
// scheduler
readonly object _threadLock = new object();
while (true)
{
if(queue.Empty)
{
Monitor.Wait(_threadLock);
}
else
{
var time = GetWaitingTimeForNextElement();
if(time > 0)
Monitor.Wait(_threadLock, time);
else
// dequeue and process element
}
}
...and pulsing when adding elements (to an empty queue or adding a new first element)?
// element enqueued
Monitor.Pulse(_threadLock);
Or with somehow chained (Task.ContinueWith(...)) Tasks using Task.Delay(int, CancellationToken )? This would need some logic to abort the waiting if a new first element is enqueued or to create a new task if no one is running. It feels like there is a simpler solution I'm not getting right now. :)
Or using a timer (very-pseudo-code, just to get the idea)...
System.Timers.Timer x = new System.Timers.Timer().Start();
x.Elapsed += (sender, args) =>
{
// dequeue and process item(s)
x.Interval = GetWaitingTimeForNextElement(); // does this reset the timer anyway?
}
...and updating the interval when adding elements (like above).
// element enqueued
x.Interval = updatedTime;
I'm also concerned with the precision of the wait methods / timers: Milliseconds is quite rough (allthough it might work) Is there a better alternative?
Ergo...
Thats again a bunch of questions/thoughts - sorry for that - but there are so many options and concerns that its hard to get an overview. So to summarize: What is the best way to implement a (precise) time scheduling system for dynamically incoming items?.
I appreciate all hints and answers! Thanks a lot.
I would suggest doing it like this:
Create a class called TimedItemsConcurrentPriorityQueue<TKey, TValue> that inherits from ConcurrentPriorityQueue<TKey, TValue>.
Implement an event called ItemReady in your TimedItemsConcurrentPriorityQueue<TKey, TValue> class that gets fired whenever an item is ready (for being processed) according to the timestamp. You can use a single timer and update the timer as needed by shadowing the Enqueue, Insert, Remove and other methods as needed (Or by modifying the source of ConcurrentPriorityQueue<TKey, TValue> and make those methods virtual so you can override them).
Instantiate a single instance of TimedItemsConcurrentPriorityQueue<TKey, TValue>, let's call that variable itemsWaitingToBecomeReady.
Instantiate a single object of BlockingCollection<T>, let's call that variable itemsReady. Use the constructor that takes an IProducerConsumerCollection<T> and pass it a new instance of ConcurrentPriorityQueue<TKey, TValue> (it inherits IProducerConsumerCollection<KeyValuePair<TKey,TValue>>)
Whenever the event ItemReady is fired in itemsWaitingToBecomeReady, you deque that item and enqueue it to itemsReady.
Process the items in itemsReady using the BlockingCollection<T>.GetConsumingEnumerable method using a new task like this:
.
Task.Factory.StartNew(() =>
{
foreach (var item in itemsReady.GetConsumingEnumerable())
{
...
}
}

How to enqueue using 1 Timer and Dequeue with another

I need to enqueue items into a Queue at roughly 4 to 8ms intervals.
Separately, my UI layer needs to dequeue, process, and display info from these items at roughly 33ms intervals (it may dequeue multiple times at that interval).
I'm not quite sure what combination of Timers and Queue I should use to get this working.
I think I should user the ConcurrentQueue class for the queue, but what timer mechanism should I use for the Enqueueing and Dequeuing?
UPDATE:
I ended up going with something like Brian Gideon's and Alberto's answers.
Without going into all the details here is what I did:
I used the following timer to for both my 4ms timer and my 33ms timer. (http://www.codeproject.com/Articles/98346/Microsecond-and-Millisecond-NET-Timer)
My 4ms timer reads data from a high speed camera, does a small amount of processing and enqueues the data into a ConcurrentQueue.
My 33ms timer dequeues all items from the queue, does some more processing on each item and sends the data to another object that computes a rolling average over some given interval. (Queues are used to manage the rolling averages.)
Within the CompositionTarget.Rendering event, I grab the value(s) from the rolling average object and plot them on my custom line graph control.
I mentioned 33ms for the UI because this data is being fed into a realtime graph. 33ms is about 30 fps... anything slower than that and some smoothness is lost.
I did end up using the ConccuentQueue as well. Works great.
CPU takes a bit of a hit. I think it's due to the high performance timers.
Thanks for the help everyone.
Those are some really tight timing requirements. I question the ~33ms value for the UI updates. The UI should not have to be updated any faster than a human can perceive it and even then that is probably overkill.
What I would do instead is to use a producer-consumer pipeline.
Producer -> Processor -> UI
In my primitive illustration above the Producer will do the step of generating the messages and queueing them. The processor will monitor this queue and do the non-UI related processing of the messages. After processing is complete it will generate messages with just enough information required to update the UI thread. Each step in this pipeline will run on a designated thread. I am assuming you do have a legitimate need for two distinct intervals (4ms and 33ms respectively). I am suggesting you add a 3rd for the UI. The polling intervals might be:
~4ms -> ~33ms -> 500ms
I used the tilde (~) intentionally to highlight the fact that lower interval timings are very hard to achieve in .NET. You might be able to hit 33ms occassionally, but the standard deviation on an arbitrary population of "ticks" will be very high using any of the timers built into the BCL. And, of course, 4ms is out of the question.
You will need to experiment with multimedia timers or other HPET (high performance event timer) mechanisms. Some of these mechanisms use special hardware. If you go this route then you might get closer to that 4ms target. Do not expect miracles though. The CLR is going to stack the deck against you from the very beginning (garbage collection).
See Jim Mischel's answer here for a pretty good write up on some of your options.
You can use one DispatcherTimer for dequeue elements and publish them to the UI and another Timer to enqueue.
For example:
class Producer
{
public readonly Timer timer;
public ConcurrentQueue<int> Queue {get;private set;}
Producer()
{
timer = new Timer(Callback, null, 0, 8);
Queue = new Concurrent<int>();
}
private void Callback(object state)
{
Queue.Enqueue(123);
}
}
class Consumer
{
private readonly Producer producer;
private readonly DispatcherTimer timer;
Consumer(Producer p)
{
producer = p;
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(33);
timer.Tick += new EventHandler(dispatcherTimer_Tick);
timer.Start();
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
int value;
if(producer.Queue.TryDequeue(out value))
{
// Update your UI here
}
}
}
Since you are dealing with the UI, you could use a couple of DispatcherTimer instead the classic timers. This timer is designed just for the interaction with the UI, thus your queue should be able to enqueue/dequeue without any problem.

Recalculating the "state" of 50 objects every second

I want to recalculate "StrategyState" of some object every second. I do not want to create a Timer for that, because at the same time, from another thread, I can access "StrategyState" property (also, Timer probably would be too heavy for my simple problem). I defined StrategyState type myself this way:
public enum StrategyState
{
OnlyKill,
Working,
ClosingStage1,
ClosingStage2,
Closed
}
I'm not sure if it will be "thread-safe" to write such object from one thread and to read from another thread.
So I was thinking to "lazy-update" my StrategyState State field, like that:
....
if ( /* State was not updated for one second or more. */ ) {
RecalculateState()
}
switch (State) {
.... // Work
How do I test state was not updated for one second or more without adding too much latency?
I can obviously create Stopwatch, but note that I need to update about 50 states totally for different objects in different threads. I'm not sure if I should add 50 Stopwatch to the system.
Probably, it's better to add one Stopwatch and share it, because I guess Stopwatch class is likely thread-safe.
What can you suggest?
Just add a DateTime for the last evaluation time:
private DateTime m_lastStateEvaluation = DateTime.MinValue;
And then
if ((DateTime.Now - m_lastStateEvaluation).TotalSeconds >= 1))
{
// Evaluate state
m_lastStateEvaluation = DateTime.Now;
}
This won't add too much time at all to the operation.
Incidentally, using a lock statement will resolve any threading issues if you use a timer. And you could have a single timer handle all 50 objects if you want.
I've implemented it like this:
private long recalculateStateTimestamp;
private const long oneSecond = 10000000;
.....
long newTime = DateTime.Now.Ticks;
if (newTime - recalculateStateTimestamp < oneSecond)
{
return;
}
recalculateStateTimestamp = newTime;
I assume this is one of the fastest ways to implement it. Also, it is partly thread-safe (enough for me).

Categories

Resources