3

私は8つのCOMポートで動作するアプリケーションを開発しています。データがCOMポートの1つから受信されると、イベントハンドラーが呼び出され、アプリケーションはCOMポート経由で受信したメッセージのラッパーを作成し、TCP経由で送信しますリモートホスト。実はラッピング後はイーサネット系ネットのどこかのデバイスに対するコマンド(測定開始コマンド)になります。

COMポートを操作するためにSerialPortとSerialDataReceivedEventHandlerを使用しています。問題は、フォームを介してすべての COM ポートに対して異なるタイムアウト (0 ~ 1000 ミリ秒) が指定されていることです。このタイムアウトの後、別のコマンドを送信して、デバイスからデータを取得する必要があります (get data コマンド)。

  • このコマンドは、8 つの COM ポートごとに異なります。
  • このコマンドは、COM ポート経由でデータを受信し、最初のコマンドを送信した後にのみ送信する必要があります。
  • 2 つのコマンド間のタイムアウトは、COM ポートごとに異なります

タイムアウトの構成について何か提案はありますか? ありがとう。

私には 1 つの考えがありますが、それが可能かどうかはわかりません。COM ポートごとに 8 つのイベント ハンドラー関数があります。

...something
sendFirstCommand();
Thread.Sleep(comPortNTimeout);
sendSecondCommand();

それらのすべてで同じ構造を使用できますか? たとえば、データ Thread.Sleep() が 2 番目のポートのハンドラーで呼び出される場合、1 番目のポートのハンドラーはフリーズしませんか?

4

1 に答える 1

2

1)各COMポートに関連するすべてのパラメータをカプセル化するある種のCommandSourceContextクラスを導入します(以下を参照)

2)他のポートイベントが発生しているときにハンドラーがフリーズするかどうかを確認するには、デバッガーでテストして、すべてのポートイベントが同じスレッドで呼び出されるかどうかを確認します。Visual Studio 2010の[スレッド]ウィンドウを使用して、COMポートイベントハンドラーにブレークポイントを設定し、現在のスレッドIDを確認するだけです。古いVisualStudioを使用している場合は、を介してアクセスするスレッドIDをログに記録するだけThread.CurrentThread.ManagedThreadIdです。したがって、異なるポートからのイベントが同じスレッドで呼び出された場合、明らかにハンドラーはそれぞれをブロックします。そうでない場合は、異なるスレッドで呼び出されるため、並行して実行されます。少なくともMSDNは(この回答の下部を参照)、データ受信イベントはメインスレッドでは発生しないと述べているため、UIコントロールにアクセスするときは注意が必要です。

interface ICommandSourceContext
{
   // Since each port has own specific command
   // we can encapsulate it in the context as well
   ICommand Command { get; }

   int PortNumber { get; }
   long TimeIntervalMilliseconds { get; }
   Action<SerialDataReceivedEventArgs> Callback { get; }     
}

// setup and add all contexts
IList<ICommandSourceContext> contexts = new List<ICommandSourceContext>();

// ideally your main code block should looks like below (this is only pseudo code)
foreach (var context in contexts)
{
   // to execute it asyncronously you can use TPL Task.Start()
   // so it would not block other handlers in case of single thread
   context.Command.Execute();
   Thread.Sleep(context.TimeIntervalMilliseconds);
}

SerialPort.DataReceivedイベントの備考

DataReceivedイベントは、SerialPortオブジェクトからデータを受信したときにセカンダリスレッドで発生しますこのイベントはメインスレッドではなくセカンダリスレッドで発生するため、UI要素など、メインスレッドの一部の要素を変更しようとすると、スレッド例外が発生する可能性があります。メインのフォームまたはコントロールの要素を変更する必要がある場合は、Invokeを使用して変更リクエストをポストバックします。これにより、適切なスレッドで作業が行われます。

于 2012-06-25T12:18:31.910 に答える