I am a software/hardware engineer with quite some experience in C and embedded technologies. Currently i am busy with writing some applications in C# (.NET) that is using hardware for data acquisition. Now the following, for me burning, question:
For example: I have a machine that has an endswitch for detecting the final position of an axis. Now i am using a USB Data acquisition module to read the data. Currently I am using a Thread to continuously read the port-status.
There is no interrupt functionality on this device.
My question: Is this the right way? Should i use timers, threads or Tasks? I know polling is something that most of you guys "hate", but any suggestion is welcome!
Polling can be employed in various computing contexts in order to control the execution or transmission sequence of the elements involved. For example, in multitasking operating systems, polling can be used to allocate processor time and other resources to the various competing processes.
Polling is the automatic process by which a node can request data from an indirect messaging coordinator.
In electronic communication, 'polling' is the continuous checking of other programs or devices by one progam or device to see what state they are in, usually to see whether they are still connected or want to communicate.
Polling is a technique where we check for fresh data over a given interval by periodically making API requests to a server. For example, we can use polling if there is data that changes frequently or we need to wait for the server to transition a given state.
IMO, this heavily depends on your exact environment, but first off - You should not use Threads anymore in most cases. Tasks
are the more convenient and more powerful solution for that.
Low polling frequency: Timer + polling in the Tick
event:
A timer is easy to handle and stop. No need to worry about threads/tasks running in the background, but the handling happens in the main thread
Medium polling frequency: Task
+ await Task.Delay(delay)
:await Task.Delay(delay)
does not block a thread-pool thread, but because of the context switching the minimum delay is ~15ms
High polling frequency: Task
+ Thread.Sleep(delay)
usable at 1ms delays - we actually do this to poll our USB measurement device
This could be implemented as follows:
int delay = 1; var cancellationTokenSource = new CancellationTokenSource(); var token = cancellationTokenSource.Token; var listener = Task.Factory.StartNew(() => { while (true) { // poll hardware Thread.Sleep(delay); if (token.IsCancellationRequested) break; } // cleanup, e.g. close connection }, token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
In most cases you can just use Task.Run(() => DoWork(), token)
, but there is no overload to supply the TaskCreationOptions.LongRunning
option which tells the task-scheduler to not use a normal thread-pool thread.
But as you see Tasks
are easier to handle (and await
able, but does not apply here). Especially the "stopping" is just calling cancellationTokenSource.Cancel()
in this implementation from anywhere in the code.
You can even share this token in multiple actions and stop them at once. Also, not yet started tasks are not started when the token is cancelled.
You can also attach another action to a task to run after one task:
listener.ContinueWith(t => ShutDown(t));
This is then executed after the listener completes and you can do cleanup (t.Exception
contains the exception of the tasks action if it was not successful).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With