Reputation: 1322
I'm writing a serial port connection handler for my application, so the user doesn't have to connect to and disconnect from the port himself/herself. Below you can see the logic and how I plan to maintain the connection.
My problem is that CPU usage skyrockets due to the while loop. How do I slow down a loop like this without it affecting other parts of the application?
Thread.Sleep()
is an obvious option. But are other parts of the application handled by the thread and affected by Thread.Sleep()
when the connection handler is started by Task.Run()
? If so, another option is to start the handler in a separate thread. But can that cause problems, when the handler is manipulating objects (like the SerialPort object) started up from a different thread?
private void StartConnectionHandler() {
Task.Run(() => ConnectionHandler());
}
private enum ConnectionState {
AwaitPortSelected,
IsPortValid,
OpenPort,
AwaitLinkStateChange,
ClosePort
}
private void ConnectionHandler() {
var connectionState = ConnectionState.AwaitPortSelected;
while (!SerialPortCts.IsCancellationRequested) {
switch (connectionState) {
case ConnectionState.AwaitPortSelected:
break;
case ConnectionState.IsPortValid:
break;
case ConnectionState.OpenPort:
break;
case ConnectionState.AwaitLinkStateChange:
break;
case ConnectionState.ClosePort:
break;
}
}
}
Upvotes: 1
Views: 294
Reputation: 939
Becareful when running long running work
in Task.Run()
. When you do Task.Run()
, by default it execute on a thread
managed by the default threadpool
.
If you do an infinite while
loop with thread.sleep(1)
, you are essentially blocking one thread of the pool. Assuming you are running with 8 logical cores, you will end up with only 7 available since you are blocking one of the thread forever. For more reading, on why this is bad. This is a good read regarding jamming the threadpool.
A better implementation would be:
Task.Factory.StartNew(() => ConnectionHandler(), TaskCreationOptions.LongRunning);
private void ConnectionHandler() {
var connectionState = ConnectionState.AwaitPortSelected;
while (!SerialPortCts.IsCancellationRequested) {
switch (connectionState) {
case ConnectionState.AwaitPortSelected:
break;
case ConnectionState.IsPortValid:
break;
case ConnectionState.OpenPort:
break;
case ConnectionState.AwaitLinkStateChange:
break;
case ConnectionState.ClosePort:
break;
Thread.Sleep(1);
}
}
}
By using TaskCreationOptions.LongRunning
. This would run your work in a dedicated thread that is not managed by the threadpool. In this case, you are safe to block the thread running ConnectionHandler()
.
Ideally, to prevent polling like this, an event-based connectionstate
notification approach would be the best approach, but i am not sure if the api/sdk you are using provided such facilities.
Upvotes: 3
Reputation: 957
Maybe use Timer
instead? You can then use its Tick
event handler and do your stuff periodically on every Tick
inside it.
Timer myTimer = new System.Windows.Forms.Timer();
// Register the tick event handler
myTimer.Tick += new EventHandler(TimerEventHandler);
// Configure timer's tick interval (in ms)
myTimer.Interval = 100;
// Run the timer
myTimer.Start();
// Event handler
private static void TimerEventHandler(Object myObject, EventArgs myEventArgs)
{
switch (connectionState) {
case ConnectionState.AwaitPortSelected:
break;
case ConnectionState.IsPortValid:
break;
case ConnectionState.OpenPort:
break;
case ConnectionState.AwaitLinkStateChange:
break;
case ConnectionState.ClosePort:
break;
}
}
Upvotes: 1