Oystein Oystein -4 years ago 68
C# Question

Serial port connection handler

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;
}
}
}

Answer Source

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.

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().

This is a good read regarding jamming the threadpool.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download