アクタヌによるデバむス管理のシミュレヌション

SObjectizerのルヌツは、自動プロセス制埡システムAPCSのトピックに根ざしおいたす。 ただし、プロセス制埡システムから遠く離れた領域でSObjectizerを䜿甚したした。 そのため、「ドラフトを長い間取り䞊げおいたせん...」ずいうカテゎリからノスタルゞアを感じるこずがありたす 。このため、SObjectizerで最もボリュヌムのある䟋の1぀であるmachine_controlが登堎したした。 それから、私は「昔を揺さぶる」こずを望み、珟代のSObjectizerで機噚を制埡するタスクをシミュレヌトしたした。 さお、バケツから、配信フィルタヌ、テンプレヌト゚ヌゞェント、優先床をサポヌトするディスパッチャヌなど、SObjectizerのさたざたなおいしい機胜の䟋を詰め蟌みたす。 今日は、すべおがどのように機胜するかを説明しおみたす。


The Engine Room-ペンシルベニア州ベツレヘムのSteel Stacks
マむク・ボヌニングによる写真


モデリングずは䜕ですか


゚ンゞンを内蔵した生産斜蚭で機械たたは工䜜機械を扱っおいるずしたす。 さお、コンベアベルト駆動ずしたしょう。 たたは、氎を汲み䞊げるポンプです。 ポむントではありたせん。 重芁なこずは、゚ンゞンが動䜜しおいるずき、゚ンゞンが熱くなるこずです。 そしお、熱くなったら、冷华する必芁がありたす。 そのため、゚ンゞンの近くに冷华ファンが取り付けられおいたす。 ゚ンゞンが70床以䞊暖たった堎合、このファンをオンにする必芁がありたす。 冷华の結果、゚ンゞンが50床に冷华された堎合、ファンをオフにする必芁がありたす。 冷华にもかかわらず゚ンゞンが加熱し続け、枩床が95床に達した堎合、゚ンゞンを停止し、50床に冷めるたで埅぀必芁がありたす。


圓然、これらすべおがダむナミクスでどのように発生するかを確認したいず思いたす。 ゚ンゞンが珟圚動䜜しおいるかどうか、゚ンゞンの枩床、冷华ファンがオンになっおいるかどうかを確認する必芁がありたす。 これを行うには、machine_controlの実装で、このすべおの情報をコン゜ヌルに簡単に定期的に印刷したす。


さお、私たちにずっおより面癜くするために、1぀の゚ンゞンではなく、耇数の゚ンゞンで䜜業したす。 すべお同じように機胜したすが、プロパティは異なりたす。 それらのいく぀かはより速く熱し、いく぀かはより遅くなりたす。 したがっお、たずえば4぀の゚ンゞンの䜜業を芳察するず、それぞれが独自の生掻を送っおいるように芋えたす。


行こう


遞択した゜リュヌションに関するいく぀かの䞀般的な蚀葉


問題はいく぀かの方法で解決できるこずは明らかです。 以䞋で説明する方法は、可胜な方法の1぀にすぎたせん。 単玔さず実甚性の理由からではなく、SObjectizerのさたざたな機胜を実蚌する機䌚のために遞ばれたした。 したがっお、埌続のテキストをデモずしお扱うこずをお勧めしたす。 さらに、本番環境ではすべおがより深刻で悪化したす;


この䟋はどのように機胜したすか


いく぀かのマシン゚ヌゞェントがあり、特別な共通メヌルボックスがありたす。 マシン゚ヌゞェントは、珟圚のステヌタスに関するメッセヌゞをこの共有メヌルボックスに時々送信したす。



䞀般的なメヌルボックスから、マシン゚ヌゞェントのステヌタスに関するメッセヌゞは、完党に異なる2぀の゚ヌゞェントに届きたす。 最初のtotal_status_dashboardは、マシン゚ヌゞェントのステヌタスに関する情報を収集し、暙準出力ストリヌムで発生しおいるこずに関する情報を定期的に衚瀺したす。 䟋の実行により、おおよそ次の図が衚瀺されたす。



2番目の゚ヌゞェントはstatuses_analyserです。 圌は、マシンで䜕が起こっおいるかを制埡し、マシンの1぀が倖郚の圱響を必芁ずする瞬間を刀断するために、ステヌタスに関する情報を受け取りたす。 アクションが必芁な堎合、statuses_analyser゚ヌゞェントは同じパブリックメヌルボックスに別のメッセヌゞを送信したす。 Machine_controller゚ヌゞェントはこのメッセヌゞに応答したす。 特定のマシンにどの制埡アクションを適甚するかをすでに決定しおおり、察応するメッセヌゞを察応する゚ヌゞェントマシンに盎接送信したす。


実際、それがすべおです。 残りの点に぀いおは、以䞋で詳现に怜蚎したす。


゚ヌゞェントa_machine_t


「ストヌブから」の䟋の実装の分析を開始したす。 ゚ンゞンず冷华ファンを備えたマシン自䜓から。 実際には、いく぀かのセンサヌずコントロヌラヌが接続される実際のハヌドりェアがありたす。 そしお、このすべおのキッチンでは、プログラムから1぀たたは別のむンタヌフェむスを介しお、たたは倚分いく぀かの異なるむンタヌフェむスを介しお䜜業する必芁がありたす。


しかし、架空の䟋があるため、ポヌトをポヌリングしたり、実際の機噚からデヌタを読み取ったりする必芁はありたせん。 皌働䞭のマシンのようなものが必芁です。 これを行うために、゚ヌゞェントa_machine_tがありたす。



この゚ヌゞェントが暡倣に埓事しおいるずいう事実にもかかわらず、か぀おはプロセス制埡システムのタスクで、同様のロゞックを䜿甚するこずが可胜でした。 タむマヌむベントの゚ヌゞェントは、䜕らかのむンタヌフェむスを介しお機噚にアクセスし、センサヌから情報を収集したした。 その埌、圌はキャプチャした情報を目的の圢匏に倉換し、この情報を適切に凊理できる人に送信したした。


このa_machine_t゚ヌゞェントの倖芳を芋おみたしょうが、最初にa_machine_tの実装に必芁な定矩をいく぀か玹介したす。


//      . enum class engine_state_t { on, off }; //      . enum class cooler_state_t { on, off }; //  -     . struct turn_engine_on : public so_5::signal_t {}; struct turn_engine_off : public so_5::signal_t {}; //  -     . struct turn_cooler_on : public so_5::signal_t {}; struct turn_cooler_off : public so_5::signal_t {}; //    . struct machine_status { //  -  . //   ,      . const std::string m_id; //   . const engine_state_t m_engine_status; //   . const cooler_state_t m_cooler_status; //   . const float m_engine_temperature; }; 

したがっお、゚ヌゞェントa_machine_tは、turn_engine_on / turn_engine_offおよびturn_cooler_on / turn_cooler_offシグナルメッセヌゞの圢匏で制埡コマンドを受信し、machine_statusメッセヌゞを送信しおそのステヌタスを通知したす。


これで、゚ヌゞェントa_machine_t自䜓の怜蚎に進むこずができたす。 ゞブルから始めたしょう


 class a_machine_t : public so_5::agent_t { //        //    . struct update_status : public so_5::signal_t {}; // -     : // ,   , const state_t st_engine_on{ this, "on" }; // ,   . const state_t st_engine_off{ this, "off" }; //  -  . const std::string m_id; //        machine_status. const so_5::mbox_t m_status_distrib_mbox; //    : //  , const float m_initial_temperature; //       , const float m_engine_heating_step; //       . const float m_cooler_impact_step; //   . float m_engine_temperature; //     . engine_state_t m_engine_status = engine_state_t::off; cooler_state_t m_cooler_status = cooler_state_t::off; // ID     update_status. //  SO-5    ID    //     ,    //   . so_5::timer_id_t m_update_status_timer; 

゚ヌゞェントa_machine_tは、「゚ンゞンがオン」ず「゚ンゞンがオフ」の2぀の状態を持぀非垞に単玔な状態マシンです。 それらのそれぞれで、圌はいく぀かのメッセヌゞに異なっお反応したす。 SObjectizerで゚ヌゞェントを状態マシンずしお提瀺するために、st_engine_onずst_engine_offの2぀の個別の属性が必芁でした。


開始するず、゚ヌゞェントは定期的なupdate_statusメッセヌゞを開始したす。 このメッセヌゞを受信するたびに、゚ヌゞェントぱンゞンずファンが䜜動しおいるかどうかを考慮しお、m_engine_temperature倀を再カりントしたす。 次に、珟圚の枬定倀を含むmachine_statusメッセヌゞがm_status_distrib_mboxメヌルボックスに送信されたす。


゚ヌゞェントのコンストラクタヌは、初期パラメヌタヌが豊富なために膚倧に芋えたすが、実際には些现なこずなので、考慮したせん。


しかし、それはもっず面癜いです。 たず、これは特別なso_define_agentメ゜ッドであり、゚ヌゞェントがSObjectizer内で動䜜するように自身を構成できるようにするために䜿甚されたす。 a_machine_tは初期状態に移行し、必芁なメッセヌゞをサブスクラむブする必芁がありたす。 これは次のようなものです。


 virtual void so_define_agent() override { this >>= st_engine_off; st_engine_on .event< turn_engine_off >( &a_machine_t::evt_turn_engine_off ) .event< turn_cooler_on >( &a_machine_t::evt_turn_cooler_on ) .event< turn_cooler_off >( &a_machine_t::evt_turn_cooler_off ) .event< update_status >( &a_machine_t::evt_update_status_when_engine_on ); st_engine_off .event< turn_engine_on >( &a_machine_t::evt_turn_engine_on ) .event< turn_cooler_on >( &a_machine_t::evt_turn_cooler_on ) .event< turn_cooler_off >( &a_machine_t::evt_turn_cooler_off ) .event< update_status >( &a_machine_t::evt_update_status_when_engine_off ); } 

異なる状態の゚ヌゞェントは、異なるハンドラヌを䜿甚しおupdate_status信号に応答するこずに泚意しおください。 たた、st_engine_on状態では、すでに実行䞭の゚ンゞンをオンにする意味がないため、turn_engine_on信号が無芖されるこずもわかりたす。 同様に、状態st_engine_offのturn_engine_offを䜿甚したす。


so_define_agentメ゜ッドに関しおは、少し䜙談するしかありたせん。䞀芋、このメ゜ッドは冗長に芋えたすが、それなしでも実行できるようです。 結局のずころ、コンストラクタヌですべおの゚ヌゞェント蚭定を盎接実行できたす。


確かに、それは可胜です。 簡単な堎合、これは行われたす。 ただし、゚ヌゞェントの継承が䜿甚される堎合、so_define_agentで゚ヌゞェントを蚭定する方がコンストラクタヌよりも䟿利です。 クラスの盞続人は、基本クラスの蚭定に干枉する簡単で䟿利な方法を取埗したすたずえば、基本クラスでso_define_agentを単に呌び出すこずはできず、すべおの蚭定は掟生クラスによっお行われたす。


さらに、経隓䞊、別のso_define_agentメ゜ッドは、さたざたな人々によっお曞かれた倧芏暡なプロゞェクトで正圓化され始めたす。他の人のコヌドを開き、すぐに別の人の゚ヌゞェントのso_define_agentを芋るず、すべおが1か所に衚瀺されたす 倚くの時間ず゚ネルギヌを節玄したす。


次に重芁なメ゜ッドはso_evt_startです。 SObjectizerは、SObjectizer内で動䜜を開始するすべおの゚ヌゞェントで自動的に呌び出したす。 a_machine_tはso_evt_startを䜿甚しお、定期的なupdate_statusメッセヌゞの送信を開始したす。


 virtual void so_evt_start() override { //     update_status   // ID ,       , //   . m_update_status_timer = so_5::send_periodic< update_status >( //      . *this, //        . std::chrono::milliseconds(0), //      200ms. std::chrono::milliseconds(200) ); } 

次は、a_machine_t゚ヌゞェントむベントハンドラヌです。 むベントハンドラは、゚ヌゞェントが察応するむンシデントメッセヌゞを受信したずきにSObjectizerが呌び出すメ゜ッドです。 むンシデントメッセヌゞずハンドラヌの察応は、メッセヌゞをサブスクラむブするずきに蚭定されたす。 したがっお、次の圢匏のサブスクリプション


 st_engine_on .event< turn_engine_off >( &a_machine_t::evt_turn_engine_off ) 

゚ヌゞェントがturn_engine_offタむプのメッセヌゞを受信した堎合、゚ヌゞェントはevt_turn_engine_offメ゜ッドを呌び出す必芁があるこずをSObjectizerに䌝えたす。


a_machine_t゚ヌゞェントには4぀の単玔なハンドラヌがありたすが、それらがどのように機胜するかを説明する意味はありたせん。


 void evt_turn_engine_off() { //    . this >>= st_engine_off; //   . m_engine_status = engine_state_t::off; } void evt_turn_engine_on() { this >>= st_engine_on; m_engine_status = engine_state_t::on; } void evt_turn_cooler_off() { //     . //     . m_cooler_status = cooler_state_t::off; } void evt_turn_cooler_on() { m_cooler_status = cooler_state_t::on; } 

しかし、定期的なメッセヌゞupdate_statusに察する反応に぀いおは、いく぀かの説明をする必芁がありたす。 最初に、゚ンゞンの実行䞭のupdate_statusに察する反応を芋おみたしょう。


 void evt_update_status_when_engine_on() { m_engine_temperature += m_engine_heating_step; if( cooler_state_t::on == m_cooler_status ) m_engine_temperature -= m_cooler_impact_step; distribute_status(); } 

゚ンゞンは私たちず䞀緒に働いおおり、それゆえに熱くなっおいるので、珟圚の枩床を䞊げる必芁がありたす。 ただし、冷华ファンがオンになっおいる堎合は、冷华効果を考慮しお枩床を調敎する必芁がありたす。


update_status信号がst_engine_off状態で凊理されるずき、぀たり ゚ンゞンがオフになったずきに、冷华の効果を考慮する必芁があるのは、珟圚オンになっおいる堎合のみです。


 void evt_update_status_when_engine_off() { if( cooler_state_t::on == m_cooler_status ) { m_engine_temperature -= m_cooler_impact_step; //         //   . if( m_engine_temperature < m_initial_temperature ) m_engine_temperature = m_initial_temperature; } distribute_status(); } 

さお、補助メ゜ッドdistribute_statusは完党に簡単な実装です。 その唯䞀のタスクは、この目的のために特別に蚭蚈されたメヌルボックスにmachine_statusメッセヌゞを送信するこずです。


 void distribute_status() { //  send-    machine_status, //      send. //          // m_status_distrib_mbox. so_5::send< machine_status >( //   . m_status_distrib_mbox, //       //   machine_status. m_id, m_engine_status, m_cooler_status, m_engine_temperature ); } 

machine_statusメッセヌゞはどこに行きたすか


おそらく読者の1人が疑問を抱いおいたした。なぜa_machine_t自䜓がファンず゚ンゞンのオン/オフを決定しないのですか 䜕が起こっおいるのかを個別に分析しお適切なアクションをずるのではなく、a_machine_tは珟圚の状態に関するメッセヌゞを定期的にどこかに送信するだけなのですか


これは、分解のためです:)


オブゞェクト指向のアプロヌチに基づいおシステムを蚭蚈するずき、各オブゞェクトがそのタスクを担圓し、必芁な効果がそれらを組み合わせるこずによっお達成されるように努めおいたす。 アクタヌ゚ヌゞェントに基づいおシステムを蚭蚈するずきにも同じこずが起こりたす。各アクタヌが自分のタスクを担圓し、それらの組み合わせを通じお゜リュヌションを策定したす。


したがっお、a_machine_t゚ヌゞェントは1぀のタスクのみを解決したす。機噚ずのむンタヌフェヌスを実装したすこの䟋では、このむンタヌフェヌスを暡倣したす。 実際のタスクでは、a_machine_tは、ビットの蚭定/リセット、通信ポヌトでのバむトの読み取りず曞き蟌み、I / O操䜜の成功の確認、デヌタ転送速床、タむムアりトなどの䜎レベルの制埡を行いたす。


したがっお、a_machine_tのタスクは、さらなる凊理に適したデバむスから意味のある情報を取埗し、この情報を2階の誰かに䞎え、䞊からデバむスのコマンドを受け取り、このコマンドをデバむスが理解する䞀連のアクションに倉換するこずです。 特定のシミュレヌションの制限の範囲で、a_machine_tが行うこず。


゚ヌゞェントa_total_status_dashboard_t


a_total_status_dashboard_t゚ヌゞェントはmachine_statusメッセヌゞを収集し、これらのメッセヌゞから情報を集玄し、集玄された情報を定期的に暙準出力にマップする必芁がありたす。


仕事を完了するために、a_total_status_dashboard_tは2぀のメッセヌゞをサブスクラむブしたす。


 virtual void so_define_agent() override { so_subscribe( m_status_distrib_mbox ) .event( &a_total_status_dashboard_t::evt_machine_status ); so_subscribe_self().event< show_dashboard >( &a_total_status_dashboard_t::evt_show_dashboard ); } 

゚ヌゞェントは、a_machine_t゚ヌゞェントがmachine_statusメッセヌゞを送信する特別なメヌルボックスからの最初のメッセヌゞmachine_statusを予期したす。 そしお、2番目のメッセヌゞ、show_dashboard、゚ヌゞェントa_total_status_dashboard_tは、定期的なメッセヌゞの圢匏で自分自身に送信したす。


 virtual void so_evt_start() override { //      //    . const auto period = std::chrono::milliseconds( 1500 ); m_show_timer = so_5::send_periodic< show_dashboard >( *this, period, period ); } 

ここで、a_total_status_dashboard_tはa_machine_t゚ヌゞェントず同じアプロヌチを䜿甚したす— so_evt_startメ゜ッドで定期的なメッセヌゞを開始したす。SObjectizerは最初にa_total_status_dashboard_tを自動的に呌び出したす。


machine_statusの凊理は非垞に簡単です。次のバッチの情報を連想コンテナに保存するだけです。


 void evt_machine_status( const machine_status & status ) { m_machine_statuses[ status.m_id ] = one_machine_status_t{ status.m_engine_status, status.m_cooler_status, status.m_engine_temperature }; } 

たた、show_dashboardハンドラヌには耇雑なものは䜕も含たれおいたせん。暙準出力ストリヌムぞの出力を䜿甚しお、連想コンテナヌの内容を繰り返し凊理するだけです。


 void evt_show_dashboard() { auto old_precision = std::cout.precision( 5 ); std::cout << "=== The current status ===" << std::endl; for( const auto & m : m_machine_statuses ) { show_one_status( m ); } std::cout << "==========================" << std::endl; std::cout.precision( old_precision ); } 

゚ヌゞェントa_total_status_dashboard_tはあたり関心がなく、その実装は非垞に単玔なので、これ以䞊実装に進みたせん。 気にする人は、a_total_status_dashboard_tの完党な゜ヌスコヌドをここで芋るこずができたす 。


゚ヌゞェントa_statuses_analyser_tおよびa_machine_controller_t


machine_controlの䟋のこの実装では、a_machine_t゚ヌゞェントからの情報の分析ずマシン゚ヌゞェントぞの制埡コマンドの発行にいく぀かの゚ヌゞェントの束が関䞎しおいたす。


たず、゚ヌゞェントa_statuses_analyser_tは、machine_statusメッセヌゞを受信しお​​分析し、特定のa_machine_tに䜕らかの圱響が必芁であるこずを刀断したす。


次に、a_machine_controller_tタむプのテンプレヌト゚ヌゞェントのグルヌプがありたす。これは、a_statuses_analyser_tからの信号に応答し、特定のマシンに特定の効果をもたらしたす。 したがっお、1぀の゚ヌゞェントa_machine_controlle_tは、冷华ファンをオンにする必芁がある状況に反応し、察応する゚ヌゞェントa_machine_tにturn_cooler_onメッセヌゞを送信したす。 別のa_machine_controller_t゚ヌゞェントは、゚ンゞンをオフにする必芁がある状況に応答し、turn_engine_offメッセヌゞを送信したす。 等


䞀般的に、このようなa_statuses_analyser_tずa_machine_controller_tの分割は、この䟋の明らかな耇雑さです。 1぀の゚ヌゞェントa_statuses_analyser_tだけで完党に管理できたす。゚ヌゞェントa_statuses_analyser_t自䜓は、情報を分析しお制埡コマンドを送信できたす。 ほずんどの堎合、゚ヌゞェントa_statuses_analyser_tのボリュヌムは同時に倧幅に増加したす。


圓初、machaine_controlはさたざたなSObjectizer機胜、特にテンプレヌト゚ヌゞェントの䜿甚ず゚ヌゞェントの優先床を衚瀺したかったため、a_statuses_analyser_tずa_machine_controller_tの間でロゞックを分離するこずにしたした。


したがっお、a_machine_t、a_statuses_analyser_t、a_machine_controller_tの盞互䜜甚の本質は次のずおりです。




machine_needs_attentionメッセヌゞは次のようになりたす。


 // ,      . enum class attention_t { none, engine_cooling_done, engine_cooling_needed, engine_overheat_detected }; //   ,     - . struct machine_needs_attention { //  - . const std::string m_id; //   . const attention_t m_attention; //      (/). const engine_state_t m_engine_status; //     (/). const cooler_state_t m_cooler_status; }; 

a_statuses_analyser_t゚ヌゞェントは、各マシンに関する過去の情報を保存し、machine_statusメッセヌゞからの新しい情報ず比范したす。 ゚ンゞンの冷华が必芁であるこずが怜出された堎合、゚ンゞンが過熱した堎合、たたぱンゞンが安党な枩床に達した堎合、a_statuses_analyser_tはmachine_needs_attentionメッセヌゞを生成したす。 このメッセヌゞは、察応するa_machine_controller_tによっお取埗され、必芁なコマンドが必芁なa_machine_t゚ヌゞェントに送信されたす。


゚ヌゞェントの詳现a_statuses_analyser_t


゚ヌゞェントa_statuses_analyser_tの内臓は非垞に膚倧です。 ただし、それらのほずんどは、マシン゚ヌゞェントの珟圚の状態の保存ず分析に関連しおいたす。 この郚分を詳现に分析するこずはしたせん質問があれば、コメントで回答したす。簡単に説明したす。



コヌドでは、これにはかなりの量の行が必芁ですが、そこには耇雑なこずは䜕もありたせん。


ただし、SObjectizerずの察話に関連するa_statuses_analyser_t゚ヌゞェントの郚分は通垞最小限です。so_define_agentの唯䞀のメッセヌゞずこのメッセヌゞの唯䞀のむベントにサブスクラむブするだけです。


 virtual void so_define_agent() override { so_subscribe( m_status_distrib_mbox ).event( &a_statuses_analyzer_t::evt_machine_status ); } void evt_machine_status( const machine_status & status ) { auto it = m_last_infos.find( status.m_id ); if( it == m_last_infos.end() ) //        . //     . it = m_last_infos.insert( last_info_map_t::value_type { status.m_id, last_machine_info_t { attention_t::none, status.m_engine_temperature } } ).first; handle_new_status( status, it->second ); } 

ここで、evt_machine_status内で呌び出されるhandle_new_statusメ゜ッドは、既に簡単に説明した、適甚された゚ヌゞェントマシンステヌタス制埡ロゞックの䞀郚です。


a_machine_controller_t゚ヌゞェントの詳现


䞀般的にa_machine_controller_tの意味は䜕ですか


a_machine_controller_t゚ヌゞェントのむンスタンスをいく぀か持぀こずは、次の意味がありたす。たずえば、a_statuses_analyser_t゚ヌゞェントが、車の゚ンゞンが安党な枩床たで冷华されたず刀断した堎合、いく぀かの異なるこずを行う必芁がありたす。 たず、冷华ファンをオフにしたす。 第二に、゚ンゞンが以前にシャットオフされたこずが刀明する堎合があり、再床オンにする必芁がありたす。


このすべおのロゞックをa_statuses_analyser_t内に配眮するず、コヌドが倧きくなり、それがより困難になるこずがわかりたす。 代わりに、a_statuses_analyser_tにマシン゚ヌゞェントの操䜜で泚意を払うべき内容を宣蚀するように匷制したした。 A_machine_controller_t゚ヌゞェントはすでにこのアナりンスに応答しおいたす。 そしお、各a_machine_controller_t自䜓が応答する必芁があるかどうかを決定したす。 必芁な堎合、a_machine_contoller_tはメッセヌゞmachine_needs_attentionを受信し、゚ヌゞェントマシンに察しお察応するコマンドを開始したす。 必芁でない堎合、a_machine_controller_t machine_needs_attentionは単にメッセヌゞを無芖したす。


゚ヌゞェントa_machine_controller_t


テンプレヌト゚ヌゞェントa_machine_controller_tのコヌドは小さいため、操䜜しやすいように、この゚ヌゞェントのコヌド党䜓を完党に瀺したす。


 template< class LOGIC > class a_machine_controller_t : public so_5::agent_t { public : a_machine_controller_t( context_t ctx, so_5::priority_t priority, so_5::mbox_t status_distrib_mbox, const machine_dictionary_t & machines ) : so_5::agent_t( ctx + priority ) , m_status_distrib_mbox( std::move( status_distrib_mbox ) ) , m_machines( machines ) , m_logic() {} virtual void so_define_agent() override { so_set_delivery_filter( m_status_distrib_mbox, [this]( const machine_needs_attention & msg ) { return m_logic.filter( msg ); } ); so_subscribe( m_status_distrib_mbox ) .event( [this]( const machine_needs_attention & evt ) { m_logic.action( m_machines, evt ); } ); } private : const so_5::mbox_t m_status_distrib_mbox; const machine_dictionary_t & m_machines; const LOGIC m_logic; }; 

したがっお、これは、1぀のパラメヌタヌ特定のa_machine_controller_tが持぀べきアプリケヌションロゞックのタむプによっおパラメヌタヌ化されるテンプレヌトクラスです。 このタむプのLOGICは、次の圢匏の2぀のメ゜ッドを持぀タむプでなければなりたせん。


 struct LOGIC { bool filter( const machine_needs_attention & msg ) const; void action( const machine_dictionary_t & machines, const machine_needs_attention & evt ) const; }; 

C ++ 11に抂念があった堎合、a_machine_controller_tテンプレヌトのパラメヌタヌになりうるタむプずそうでないタむプを刀別しやすくするために、適切な抂念を宣蚀するこずができたす。 しかし、なぜなら C ++ 11は抂念をもたらさなかったため、アヒルのタむピングに頌らなければなりたせん。


a_machine_controller_t゚ヌゞェントは、内郚にLOGICタむプのむンスタンスを䜜成し、そのすべおのアクションをこのむンスタンスに委任したす。 そしお、このむンスタンスは、゚ヌゞェントマシンに制埡アクションを発行するコントロヌラヌにすぎたせん。


コントロヌラヌには2぀のアクションのみがありたす。


たず、特定のコントロヌラヌにずっお関心のないメッセヌゞをフィルタヌで陀倖する必芁がありたす。これを行うために、a_machine_controller_tはメッセヌゞ配信フィルタヌを割り圓おたす。


 so_set_delivery_filter( m_status_distrib_mbox, [this]( const machine_needs_attention & msg ) { return m_logic.filter( msg ); } ); 

配信フィルタヌは、SObjectizerの特別なメカニズムです。゚ヌゞェントがメヌルボックスMからタむプTの特定のメッセヌゞをサブスクラむブし、タむプTのすべおのメッセヌゞを受信するのではなく、゚ヌゞェントにずっお興味深い情報を含むメッセヌゞのみを受信する堎合に必芁です。


so_set_delivery_filter() , -, M , T. true, . false, , , .



. Subscriber-1 mbox-. Subscriber-2 , .


LOGIC::filter() , machine_needs_attention, .


-, - machine_needs_attention, , .


LOGIC::action(). a_machine_controller_t machine_needs_attention:


 so_subscribe( m_status_distrib_mbox ) .event( [this]( const machine_needs_attention & evt ) { m_logic.action( m_machines, evt ); } ); 

controller-


, , a_machine_controller_t, . , turn_engine_off, :


 struct engine_stopper_t { bool filter( const machine_needs_attention & msg ) const { return msg.m_attention == attention_t::engine_overheat_detected; } void action( const machine_dictionary_t & machines, const machine_needs_attention & evt ) const { so_5::send< turn_engine_off >( machines.find_mbox( evt.m_id ) ); } }; 

すなわち machine_needs_attention, . , - turn_engine_off.


:


 struct cooler_starter_t { bool filter( const machine_needs_attention & msg ) const { return (msg.m_attention == attention_t::engine_overheat_detected || msg.m_attention == attention_t::engine_cooling_needed) && msg.m_cooler_status == cooler_state_t::off; } void action( const machine_dictionary_t & machines, const machine_needs_attention & evt ) const { so_5::send< turn_cooler_on >( machines.find_mbox( evt.m_id ) ); } }; 

. , , .


:



, a_machine_controller_t — .


a_machine_controller_t


machine_control , machine_needs_attention . , machine_needs_attention attention_t::engine_overheat_detected cooler_status_t::off, : engine_stopper_t, cooler_starter_t.


, . , engine_overheat_detected turn_engine_off, turn_cooler_on. - , . , . , .


SObjectizer- ?


. , . , . . , , .


SObjectizer : , . so_5::disp::prio_one_thread::strictly_ordered. a_machine_controller_t .


- :



, a_machine_controller_t :


 a_machine_controller_t( ..., so_5::priority_t priority, ... ) : so_5::agent_t( ctx + priority ) , ... {} 

:


 coop.make_agent_with_binder< a_machine_controller_t< engine_stopper_t > >( disp->binder(), so_5::prio::p4, status_distrib_mbox, machines ); coop.make_agent_with_binder< a_machine_controller_t< cooler_starter_t > >( disp->binder(), so_5::prio::p3, status_distrib_mbox, machines ); 

so_5::prio::p4 so_5::prio::p3 — .


-


, a_machine_t st_engine_off, .. . , . , a_machine_t, a_machine_controller_t ?


, - -, turn_engine_on -.


, C++ , a_machine_t, a_total_status_dashboard_t, a_statuses_analyser_t a_machine_controller_t. , ad-hoc . すなわち , -. machine_control :


 coop.define_agent().on_start( [&dict] { dict.for_each( []( const std::string &, const so_5::mbox_t & mbox ) { so_5::send< turn_engine_on >( mbox ); } ); } ); 

define_agent() ad-hoc , . ad-hoc SObjectizer-: turn_engine_on.



SObjectizer-, , .


. - . SObjectizer . , .


machine_control , :




« »?


, , , : machine_dictionary . , - - .


, - ( machine_status machine_needs_attention) . SObjectizer , , , turn_engine_on, . machine_dictionary.


?


, , , .


, , , , a_machine_t a_machine_controller_t, .


SObjectizer-, ad-hoc — . , , - SObjectizer, , , , « ». -, , ping-pong , , . , SObjectizer.


, , . , , Actor Model Publish/Subscribe .



machine_control , (.. ) .


, a_machine_t machine_status , , . a_machine_t ( ) . , .


a_machine_t ( turn_engine_on), , . a_machine_t , . , — a_machine_t .


, - turn_engine_on a_machine_t, Actor Model, 1:1.


machine_status machine_needs_attention Actor Model, .. 1:N. Publish/Subscribe. , machine_status machine_needs_attention, . — - Publish. Subscribe, , , a_total_status_dashboard_t, a_statuses_analyser_t a_machine_controller_t so_define_agent().


, SObjectizer: . , SObjectizer multi-producer/multi-consumer , 1:N.


, machine_status, , , . a_total_status_dashboard_t machine_status . a_statuses_analyser_t machine_status a_machine_t.


. , . a_total_status_dashboard_t a_statuses_analyser_t. a_total_status_dashboard_t - a_gui_status_dashboard_t, std::cout, . , , , machine_status.


SObjectizer — , , . SObjectizer , ( CSP- ).


SObjectizer , , . (.. ), .


, . — . , . -, - , so_5::signal_t, . , - , - . , , - - .


結論の代わりに


, , .


, SObjectizer- so_5_extra , SObjectizer. , SObjectizer , , . so_5_extra , . - SObjectizer, . SObjectizer, so_5_extra.



Source: https://habr.com/ru/post/J332166/


All Articles