클래스를 설계할 때, 1초 마다 doSomething() 을 호출하면서, 동시에 외부에서 들어오는 evExternalEvent를 처리하게 하도록 아래와 같이 State Chart Diagram을 설계했었다.
결과적으로는 잘못된 설계이다. evExternalEvent가 1초 보다 빠르게 들어온다면 위와 같은 상황에서는 절대 타이머 이벤트가 발생하지 않을 것이다. 이유는 생성된 코드를 보면 확인할 수 있다. doSomethingElse()가 호출됨과 동시에 타이머를 다시 세팅하고있다.
해결책은 아래와 같이 두가지 방법이 있을 수 있다.(물론 더 있을 수도!)
방법1) Reactions In State 사용
생성된 코드는 아래와 같다. 최초에 타이머를 리셋하던 코드가 사라진것을 볼수 있을 것이다.
방법2) Sub-state 사용
방법1, 방법2 와 같이 설계를 수정한다면, 외부 이벤트의 영향없이 원하는 타이머 동작을 볼 수 있을 것이다.
결과적으로는 잘못된 설계이다. evExternalEvent가 1초 보다 빠르게 들어온다면 위와 같은 상황에서는 절대 타이머 이벤트가 발생하지 않을 것이다. 이유는 생성된 코드를 보면 확인할 수 있다. doSomethingElse()가 호출됨과 동시에 타이머를 다시 세팅하고있다.
IOxfReactive::TakeEventStatus SomeClass::rootState_processEvent() {
IOxfReactive::TakeEventStatus res = eventNotConsumed;
if(rootState_active == running)
{
if(IS_EVENT_TYPE_OF(evExternalEvent_Default_id))
{
if(rootState_timeout != NULL)
{
rootState_timeout->cancel();
rootState_timeout = NULL;
}
//#[ transition 1
doSomethingElse();
//#]
rootState_subState = running;
rootState_active = running;
rootState_timeout = scheduleTimeout(1000, NULL);
res = eventConsumed;
}
else if(IS_EVENT_TYPE_OF(OMTimeoutEventId))
{
if(getCurrentEvent() == rootState_timeout)
{
if(rootState_timeout != NULL)
{
rootState_timeout->cancel();
rootState_timeout = NULL;
}
//#[ transition 0
doSomething();
//#]
rootState_subState = running;
rootState_active = running;
rootState_timeout = scheduleTimeout(1000, NULL);
res = eventConsumed;
}
}
}
return res;
}
IOxfReactive::TakeEventStatus res = eventNotConsumed;
if(rootState_active == running)
{
if(IS_EVENT_TYPE_OF(evExternalEvent_Default_id))
{
if(rootState_timeout != NULL)
{
rootState_timeout->cancel();
rootState_timeout = NULL;
}
//#[ transition 1
doSomethingElse();
//#]
rootState_subState = running;
rootState_active = running;
rootState_timeout = scheduleTimeout(1000, NULL);
res = eventConsumed;
}
else if(IS_EVENT_TYPE_OF(OMTimeoutEventId))
{
if(getCurrentEvent() == rootState_timeout)
{
if(rootState_timeout != NULL)
{
rootState_timeout->cancel();
rootState_timeout = NULL;
}
//#[ transition 0
doSomething();
//#]
rootState_subState = running;
rootState_active = running;
rootState_timeout = scheduleTimeout(1000, NULL);
res = eventConsumed;
}
}
}
return res;
}
해결책은 아래와 같이 두가지 방법이 있을 수 있다.(물론 더 있을 수도!)
방법1) Reactions In State 사용
생성된 코드는 아래와 같다. 최초에 타이머를 리셋하던 코드가 사라진것을 볼수 있을 것이다.
IOxfReactive::TakeEventStatus SomeClass::rootState_processEvent() {
IOxfReactive::TakeEventStatus res = eventNotConsumed;
if(rootState_active == running)
{
if(IS_EVENT_TYPE_OF(evExternalEvent_Default_id))
{
//#[ transition 1
doSomethingElse();
//#]
res = eventConsumed;
}
else if(IS_EVENT_TYPE_OF(OMTimeoutEventId))
{
if(getCurrentEvent() == rootState_timeout)
{
if(rootState_timeout != NULL)
{
rootState_timeout->cancel();
rootState_timeout = NULL;
}
//#[ transition 0
doSomething();
//#]
rootState_subState = running;
rootState_active = running;
rootState_timeout = scheduleTimeout(1000, NULL);
res = eventConsumed;
}
}
}
return res;
}
IOxfReactive::TakeEventStatus res = eventNotConsumed;
if(rootState_active == running)
{
if(IS_EVENT_TYPE_OF(evExternalEvent_Default_id))
{
//#[ transition 1
doSomethingElse();
//#]
res = eventConsumed;
}
else if(IS_EVENT_TYPE_OF(OMTimeoutEventId))
{
if(getCurrentEvent() == rootState_timeout)
{
if(rootState_timeout != NULL)
{
rootState_timeout->cancel();
rootState_timeout = NULL;
}
//#[ transition 0
doSomething();
//#]
rootState_subState = running;
rootState_active = running;
rootState_timeout = scheduleTimeout(1000, NULL);
res = eventConsumed;
}
}
}
return res;
}
방법2) Sub-state 사용
방법1, 방법2 와 같이 설계를 수정한다면, 외부 이벤트의 영향없이 원하는 타이머 동작을 볼 수 있을 것이다.