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

long running workTask.Run()で実行しているときに十分です。 Task.Run()を実行すると、既定ではで実行され、既定値はthreadpoolです。

で無限のwhileループを実行すると、本質的にプールの1つのスレッドがブロックされます。 8つの論理コアを使っていると仮定すると、スレッドの1つを永久にブロックしているので、7つの論理コアしか使用できなくなります。もっと読むために、なぜこれが悪いのか。

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

​​を使用することにより:これは、より高度な実装は次のようになりa good read regarding jamming the threadpool.

です。これは、スレッドプールによって管理されていない専用スレッドで作業を実行します。この場合、ConnectionHandler()を実行しているスレッドをブロックすることは安全です。

理想的には、このようなポーリングを防ぐために、イベントベースのconnectionstate通知方法が最適なアプローチですが、使用しているapi/sdkがそのような機能を提供しているかどうかはわかりません。

+0

助けてくれてありがとう、threadpoolsの情報へのリンク。私は今それを調べている。しかし、デフォルトのスレッドプールの外に新しいスレッドを作成すると、アプリケーション内の他のオブジェクトとのやり取りにどのように影響しますか? 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

関連する問題