1

問題定義:

Linux を実行する産業用組み込みシステム用のアプリケーションを設計しています。

システムは、外界からのイベントによって駆動されます。システムへの入力は、次のいずれかになります。

  1. デジタル IO ラインの形でのシステムへの入力はほとんどありません (e-stop のようなプロセッサの GPIO に接続されています)。
  2. このシステムは、システムを Web ブラウザ経由で制御できるようにする Web サーバーを実行します。
  3. システムは TCP サーバーを実行します。どの PC または HMI デバイスも、TCP/IP 経由でコマンドを送信できます。

システムは、Modbus を使用して UART 経由で RS485 スレーブ デバイスを駆動または制御する必要があります。システムは、クーラーのオン/オフなどのいくつかの IO ラインも制御する必要があります。このアプリケーションを定義するには、ステート マシンが不可欠であると考えています。コアアプリケーションは、次のスレッドを持つマルチスレッドアプリケーションでなければなりません...

  1. メインスレッド
  2. RS485 スレーブを制御するスレッド。
  3. Web インターフェイスからのイベントを処理するスレッド。
  4. デジタル I/O イベントを処理するスレッド。
  5. TCP/IP(ソケット)経由でコマンドを処理するスレッド

スレッド間通信には、Pthread 条件シグナル & 待機を使用しています。初期の設計アプローチ (メイン スレッドに 1 つのステート マシン) に従って、システムへの入力イベント (Web または tcp/ip またはデジタル I/O) はメイン スレッドに中継され、適切なスレッドと通信する必要があります。イベントは予定です。一般的なシナリオは、Web インターフェイスを介して RS485 スレーブのステータスを取得することです。この場合、Web インターフェイス スレッドはイベントをメイン スレッドにリレーし、メイン スレッドは状態を変更してから、RS485 スレーブを制御して応答するスレッドにイベントを伝達します。メイン スレッドは、応答を Web インターフェイス スレッドに送り返します。

質問:

  1. 各スレッドに独自のステート マシンを持たせて、メイン スレッドの複雑さを軽減する必要がありますか? そのような場合でも、メイン スレッドにステート マシンを用意する必要がありますか?
  2. 入力イベントを処理するスレッドは、メインスレッドをバイパスしてイベントを処理するスレッドと直接通信できますか? たとえば、Web インターフェイス スレッドは、RS485 スレーブを制御するスレッドと直接通信できますか?
  3. pthread 条件シグナルを使用してスレッド間通信を待機しても問題ありませんか、それともより良いアプローチがありますか?
  4. 外部からのイベントと他のスレッドからの応答を 1 つのスレッドで待機させるにはどうすればよいでしょうか。たとえば、Web インターフェイス スレッドは通常、Web サーバーの CGI ビンからのプロセス間通信のために、POSIX メッセージ キューでイベントを待ちます。CGI ビンは、このメッセージ キューを介して Web インターフェイス スレッドにイベントを送信します。このイベントを処理するとき、Web インターフェイス スレッドは他のスレッドからの応答を待ちます。このような状況では、前のイベントの処理が完了し、POSIX メッセージ キューでの待機に戻るまで、Web インターフェイスからの新しいイベントを処理できませんでした。

説明が長すぎて申し訳ありません...他の人が理解して助けてくれるように、可能な限り最善の方法で説明を進めたことを願っています。

必要に応じて、さらに情報を提供できます。

4

2 に答える 2

3

このような要件に対して私が常に試みているのは、1 つの「SM」スレッドによって実行される 1 つのステート マシンを使用することです。これはメイン スレッドになる可能性があります。このスレッドは、'EventQueue' 入力プロデューサー/消費者キューをタイムアウトで待機します。タイムアウトは、必要に応じてタイムアウト イベントをステート マシンに提供できる内部デルタ キューを実行するために使用されます。

他のすべてのスレッドは、メッセージを EventQueue にプッシュすることによって状態エンジンにイベントを伝達し、SM スレッドはそれらをシリアルに処理します。

SM 内のアクション ルーチンが何かを実行する必要があると判断した場合、何かを同期的に待機してはならないため、実行可能なスレッド/サブシステムの入力キューに要求メッセージをプッシュしてアクションを要求する必要があります。

私のメッセージ クラス (OK、C の場合は *struct) には通常、「コマンド」列挙型、「結果」列挙型、データ バッファー ポインター (大量のデータを転送する必要がある場合)、エラー メッセージ ポインター、 (エラーがない場合は null)、およびあらゆる種類の要求の非同期キューイングを許可し、完全な結果 (成功または失敗) を返すために必要なその他の状態。

このメッセージ パッシングの 1 つの SM 設計は、デッドロック、制御されていない通信、および反復不可能でデバッグ不可能な相互作用の悪夢の世界に入ることなく、柔軟で拡張可能な方法でそのようなタスクを実行できる唯一のものです。

どのような設計についても最初に尋ねるべき質問は、「わかりました。奇妙な問題が発生した場合、システムをどのようにデバッグできますか?」です。上記の設計では、すぐに答えることができます。「SM スレッドでデキューされたすべてのイベントをログに記録します。それらはすべて連続して受信されるため、それらに基づいてどのようなアクションが実行されるかを常に正確に把握できます」。他の設計が提案されている場合は、上記の質問をしてください。すぐに良い答えが得られない場合は、決して機能しません。

そう:

  1. スレッドまたはスレッド化されたサブシステムが、別のステートマシンを使用して独自の内部機能を実行できる場合は、問題ありません。これらの SM は、システムの残りの部分から見えないようにする必要があります。

  2. いいえ!

  3. pthread 条件シグナルと待機を使用して、プロデューサー/コンシューマー ブロッキング キューを実装します。

  4. スレッド/サブシステムごとに 1 つの入力キュー。すべての入力は、メッセージの形でこのキューに送られます。各メッセージのコマンド/状態は、メッセージとそれに対して何をすべきかを識別します。

ところで、ショットガンアットヘッドでない限り、私はこれをC++で100%行います:)

于 2013-08-21T13:12:30.197 に答える
1

もともとターミナル コントローラのクローン ( EC115/EC270)用に作成された従来の組み込みライブラリを実装しました。Siemens ES122CこのライブラリとOSには、あなたが説明したものが多かれ少なかれ含まれていました。オリジナルのハードウェアは 80186 CPU に基づいていました。RMOSシーメンスにとって、私たちにとってのOS FXMOS(公開されたことがないことをググらないでください)には、基本的なコントローラーの作業に必要なすべてのものが含まれていました。プリエンプティブ マルチタスク、タスク間通信、セマフォ、タイマー、I/O イベントを備えていましたが、メモリ保護はありませんでした。私はそれを RaspberryPi (つまり Linux) に移植しました。

pthread を使用して従来の「タスク」をシミュレートしました。メモリ保護がなかったため、スレッドが意味的に最も近いものです。実装の残りの部分は、epollAPI を中心にしています。これは、すべてがイベントを生成することを意味します。イベントとは、何かが発生したとき、タイマーが切れたとき、別のスレッドがデータを送信したとき、TCP ソケットが接続されたとき、IO ピンの状態が変化したときなどです。これには、すべてのイベント ソースをファイル記述子に変換する必要があります。Linux には、まさにそれを行う syscall がいくつか用意されています。タスク間の通信には、従来の Unix パイプを使用しました。タイマーイベントにはtimerfdAPIを使用しました。TCP 通信には通常のソケットを使用しました。シリアル I/OI の場合は、適切なデバイスを開いただけ/dev/???です。私の場合、シグナルは必要ありませんが、Linux は必要に応じて「signalfd」を提供します。

次にepoll_wait、元のセマンティックをシミュレートするために折り返しました。

私は魔法のように働きます。

TL;DR

epollおそらく必要なことを行うAPIを詳しく見てください。

編集: はい、Martin James のアドバイスは特に 4 が非常に優れています。

于 2014-03-24T07:17:34.787 に答える