バグ #3697
未完了
ECにアタッチされたRTCが即座に追加されないためACTIVATE時に適切に遷移しない問題
n-ando さんが8年以上前に追加.
8年以上前に更新.
説明
金広です。
ありがとうございます。
動くようになってきました。
ただまだ問題があります。
rtc1,rtc2,rtc3と3つのコンポーネントを作って、rtc1の実行コンテキストを使って
rtc2,rtc3も直列実行するように設定すると、
https://github.com/fkanehiro/hrpsys-base/blob/master/python/rtm.py#L454
rtc1,rtc2,rtc3という順序でactivateすれば問題ないのですが、rtc3,rtc2,rtc1と
いう順序でactivateすると、rtc3とrtc2はACTIVE_STATEに遷移しません。
この辺りも何か作法に変更あったのでしょうか。
ロボットソフトウェアプラットフォーム研究チームの宮本と申します。
実行コンテキストで複数のコンポーネントを実行する際にactivateする順序によって一部のコンポーネントがACTIVE_STATEに遷移しない問題ですが、原因を特定できたのでご報告いたします。
まず実行コンテキストにアタッチしたコンポーネントはExecutionContextWorkerクラスのm_compsという配列に追加されるのですが、ExecutionContextインターフェースのadd_componentで実行コンテキストにコンポーネントを追加しようとても即座にはm_compsにコンポーネントは追加されません。
この時点では別の配列に格納しておいて、updateComponentListという関数が呼び出された時点でm_compsに追加されます。
コンポーネントの処理実行中にコンポーネントの追加をしないようにするために、このようになっています。
> rtc1,rtc2,rtc3という順序でactivateすれば問題ないのですが、rtc3,rtc2,rtc1と
> いう順序でactivateすると、rtc3とrtc2はACTIVE_STATEに遷移しません。
updateComponentList関数はinvokeWorkerDoという関数で呼び出されていて、invokeWorkerDo関数はPeriodicExecutionContextのsvc関数で呼び出されています。
ただ全てのコンポーネントがINACTIVE_STATEの場合、以下の箇所で処理が止められてしまいinvokeWorkerDo関数が実行されずupdateComponentList関数も実行されません。
int PeriodicExecutionContext::svc(void)
{
(省略)
Guard guard(m_workerthread.mutex_);
while (!m_workerthread.running_)
{
m_workerthread.cond_.wait();
//ここで止められているため下のinvokeWorkerDo関数は実行されず、updateComponentList関数も実行されない
//既にアタッチしたコンポーネントをアクティブにするとsignal関数が呼び出されて下の処理が実行される
}
}
coil::TimeValue t0(coil::gettimeofday());
ExecutionContextBase::invokeWorkerDo();
ExecutionContextBase::invokeWorkerPostDo();
coil::TimeValue t1(coil::gettimeofday());
既にアタッチしてあるコンポーネントをactivateした場合、invokeWorkerDo関数が呼び出されてupdateComponentList関数も呼び出されるのでコンポーネントが追加されます。
rtc1をrtc2、rtc3より先にactivateした場合にはm_compsにrtc2、rtc3が追加されているのでACTIVE_STATEに遷移しますが、rtc2、rtc3を先にactivateした場合はこの時点でm_compsにrtc2、rtc3が追加されておらずコンポーネントを見つけられずに失敗します。
全てのコンポーネントがINACTIVE_STATEの時にコンポーネントを追加しても問題はないので、今後修正する予定です。
よろしくお願いします。
ExecutionContextWorker--<>ExecutionContextBase<|---PeriodicExecutionContext
- PeriodicExecutionContext では参加しているすべてのRTCがINACTIVEの時スレッドを止める。
- ExecutionContextWorker::addComponent/removeComponent ではスレッドが動いているときには、コンポーネントの参照を保持するリストを更新せず、1周期回り切ったときにリストの更新を行う。
- リストの更新を行う関数 ExecutionContextWorker::updateComponentList() は1)isRunning()==falseの時(ECのstateがstoppingの時)、またはスレッドが1周期回り切ったときのみ
- スレッドが止まっているため、後から追加されたコンポーネントはリストに追加されず、RTCにアタッチもされないためACTIVEにならない。
解決策¶
- ExecutionContextBase::onAdded(Removed)Component() 等のテンプレート関数を利用
- これらの関数にaddComponent/removeComponent時に実行したい内容を追加することが可能
- PeriodicExecutionContext のスレッドが止まっているときには m_worker.updateComponentList() を呼ぶようにする
- updateComponentList() はprotected なので、そのままではPeriodicECでは呼べない
- mutexをモジュール化することはできないので、あきらめてpublicに変更
テスト¶
examples/Composite のSensorCompを利用して、初期化関数を以下のように変更
- ControllerとMotorはrtc.confで.soをロードしておく。
- 以下のように、SensorのECを取り出し、Controller, Motor にアタッチ
- Motor, Controller, Sensor の順で activate した。
void MyModuleInit(RTC::Manager* manager)
{
+ std::cout << "1" << std::endl;
SensorInit(manager);
- RTC::RtcBase* comp;
+ std::cout << "2" << std::endl;
+ RTC::RtcBase* scomp;
+ std::cout << "3" << std::endl;
+ RTC::RtcBase* ccomp;
+ std::cout << "4" << std::endl;
+ RTC::RtcBase* mcomp;
+ std::cout << "5" << std::endl;
// Create a component
- comp = manager->createComponent("Sensor");
+ scomp = manager->createComponent("Sensor");
+ std::cout << "6" << std::endl;
+ RTC::RTObject_ptr srtc = scomp->getObjRef();
+ std::cout << "7" << std::endl;
+ ccomp = manager->createComponent("Controller");
+ std::cout << "8" << std::endl;
+ RTC::RTObject_ptr crtc = ccomp->getObjRef();
+ std::cout << "9" << std::endl;
+ mcomp = manager->createComponent("Motor");
+ std::cout << "10" << std::endl;
+ RTC::RTObject_ptr mrtc = mcomp->getObjRef();
+ std::cout << "11" << std::endl;
+
+ RTC::ExecutionContextList_var ecs = srtc->get_owned_contexts();
+ std::cout << "12" << std::endl;
+ ecs[0]->add_component(crtc);
+ std::cout << "13" << std::endl;
+ ecs[0]->add_component(mrtc);
+ std::cout << "14" << std::endl;
+
+ ecs[0]->activate_component(mrtc);
+ std::cout << "15" << std::endl;
+ ecs[0]->activate_component(crtc);
+ std::cout << "16" << std::endl;
+ ecs[0]->activate_component(srtc);
+ std::cout << "17" << std::endl;
+
変更前
n-ando@ubuntu1404:~/work/OpenRTM-aist/ec_bug/trunk/OpenRTM-aist/examples/Composite$ ./SensorComp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Sensor Activated
17
変更後
^Cn-ando@ubuntu1404:~/work/OpenRTM-aist/ec_bug/trunk/OpenRTM-aist/examples/Compote$ ./SensorComp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Motor Activated
15
Controller Activated
16
Sensor Activated
17
^Cn-ando@ubuntu1404:~/work/OpenRTM-aist/ec_bug/trunk/OpenRTM-aist/examples/Compote$
Motor, Controller, Sensor の順でも activate できている。
他の形式にエクスポート: Atom
PDF