まずSerialPort
、フレームワークに付属のクラスを使用すると、データ受信イベントはすでに非同期になっています。何かを送信すると、データは非同期で入ってきます。
私が試したいのは、回答を待つ必要があるすべてのリクエストをキューに入れることです。全体的な受信ハンドラーで、受信データが要求の 1 つに対する応答であるかどうかを確認します。その場合は、リクエスト情報とともに返信を保存します (そのための何らかの状態クラスを作成します)。他のすべての着信データは通常どおり処理されます。
では、リクエストが応答を待つようにするにはどうすればよいでしょうか。コマンドを送信して応答を返す呼び出しは、状態オブジェクトを作成し、それをキューに入れ、応答が受信されたかどうかを確認するためにオブジェクトを監視します。応答があった場合、呼び出しは結果を返します。
考えられる概要は次のとおりです。
string SendAndWait(string command)
{
StateObject state = new StateObject(command);
state.ReplyReceived = new ManualResetEvent(false);
try
{
SerialPortHandler.Instance.SendRequest(command, state);
state.ReplyReceived.WaitOne();
}
finally
{
state.ReplyReceived.Close();
}
return state.Reply;
}
なにSerialPortHandler
?Instance
これを、シングルトン インスタンスにアクセスするためのプロパティを含むシングルトン クラスにします。このクラスは、すべてのシリアル ポート関連の処理を行います。また、「帯域外」情報 (コマンドへの応答ではないデータ) が入ったときに発生するイベントも含める必要があります。
またSendRequest
、コマンドをシリアル デバイスに送信し、状態オブジェクトを内部リストに格納し、コマンドの応答が来るのを待ち、応答で状態オブジェクトを更新するメソッドも含まれています。
状態オブジェクトには、状態オブジェクトのプロパティを変更ReplyReceived
した後に設定される、呼び出される待機ハンドルが含まれています。そうすれば、ループと. また、呼び出す代わりに、応答が来るまで待機するミリ秒数で呼び出すこともできます。このようにして、ある種のタイムアウト機能を実装できます。SerialPortHandler
Reply
Thread.Sleep
WaitOne()
WaitOne(timeout)
timeout
これは、次のようになりますSerialPortHandler
。
void HandlePossibleCommandReply(string reply)
{
StateObject state = FindStateObjectForReply(reply);
if (state != null)
{
state.Reply = reply;
state.ReplyReceived.Set();
m_internalStateList.Remove(state);
}
}
注意してください:これは私が始めようとするものです。これは非常に最適化できると確信していますが、ご覧のとおり、「マルチスレッド」があまり関係していませんSendAndWait
。別のクライアントがまだ応答を待っている間に複数のクライアントがコマンドを発行できるように、メソッドのみを呼び出す必要があります。
編集
別の注意: メソッドは WCF サービスの基礎を形成する必要があると言っています。これにより、サービスを正しく構成した場合、サービスへの呼び出しごとにサービスクラスのインスタンスが作成されるため、SendAndWait
メソッドがサービスの独自のインスタンスで「ライブ」になり、必要さえなくなるため、作業が簡単になります。まったく再入可能です。その場合、SerialPortHandler
現在サービス クラスのインスタンスが存在するかどうかに関係なく、 が常にアクティブであること (=> が作成され、実際の WCF サービスとは独立して実行されていること) を確認する必要があります。
編集 2
コメントで提案されているように、サンプル コードをループおよびスリープしないように変更しました。