2017-06-13 99 views
1

我正在为我的应用程序编写一个串行端口连接处理程序,因此用户不必自行连接到端口和从端口断开连接。您可以在下面看到我的计划维护连接的逻辑和方式。串行端口连接处理程序

我的问题是,由于while循环,CPU使用率高涨。如何减缓这样的循环,而不影响应用程序的其他部分?

Thread.Sleep()是一个明显的选择。但是,线程是否处理了其他应用程序,并且在连接处理程序由Task.Run()启动时受到Thread.Sleep()的影响?如果是这样,另一种选择是在单独的线程中启动处理程序。但是,当处理程序正在操作对象(如SerialPort对象)从不同的线程启动时,会导致问题吗?

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

如果我想自动处理与端口的连接(例如,如果用户选择使用不同的端口),我确实需要一个(或使用Timer作为@pitersmx建议)。另外我有一个处理接收数据的事件处理程序。 – Oystein

回答

3

Task.Run()中运行long running work时会出现问题。当您执行Task.Run()时,默认情况下它会在由默认threadpool管理的thread上执行。

如果你用thread.sleep(1)做了一个无限的while循环,你实际上阻塞了一个线程池。假设你正在运行8个逻辑内核,你将最终只有7个可用,因为你永远阻塞了一个线程。为更多阅读,为什么这是不好的。这是a good read regarding jamming the threadpool.

一个更好的实现是:

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

通过使用​​。这可以在不受线程池管理的专用线程中运行你的工作。在这种情况下,您可以安全地阻止运行ConnectionHandler()的线程。

理想情况下,为了防止这样的投票,基于事件的connectionstate通知方法将是最好的方法,但我不确定您使用的api/sdk是否提供了此类功能。

+0

感谢您的帮助,并链接到线程池的信息。我现在正在研究它。但是,如何在默认线程池之外创建新线程影响与应用程序中其他对象的交互,例如SerialPort对象,VM等?另外,TaskCreationsOption数据类型应该是TaskCreationOptions。 – Oystein

1

也许用Timer代替?然后,您可以使用它的Tick事件处理程序,并在其内部的每个Tick上定期执行您的操作。

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

} 
+1

谢谢你的提示!我想我现在将它作为一个Task.Run(),但我会牢记你的想法。 – Oystein