2017-06-13 102 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