Oystein
Oystein

Reputation: 1322

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

Upvotes: 1

Views: 294

Answers (2)

Misterhex
Misterhex

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

pitersmx
pitersmx

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

Related Questions