문제

나는 상태가 거의 3개 없는 실시간 시스템에 상태 머신을 가지고 있습니다.

typedef enum {
    STATE1,
    STATE2,
    STATE3
} state_t;

그러나 해당 상태 간의 전환에는 상당한 시간이 필요하며 자체 하위 구분이 있습니다.따라서 두 가지 선택이 있습니다. 하나는 모든 중간 상태가 표시되도록 기본 상태 시스템을 확장하는 것입니다.

typedef enum {
    STATE1,
    STATE1_PREPARE_TRANSITION_TO_STATE2,
    STATE1_DO_TRANSITION_TO_STATE2,
    STATE1_PREPARE_TRANSITION_TO_STATE3,
    STATE1_DO_TRANSITION_TO_STATE3,
    STATE2,
    ...
} state_t;

또는 관련 주요 상태에 대해 중첩된 상태 머신을 생성합니다.

typedef enum {
    STATE1_NOT_ACTIVE,
    STATE1_NORMAL,
    STATE1_PREPARE_TRANSITION_TO_STATE2,
    STATE1_DO_TRANSITION_TO_STATE2,
    STATE1_PREPARE_TRANSITION_TO_STATE3,
    STATE1_DO_TRANSITION_TO_STATE3
} sub_state1_t;
...

두 가지 가능성 모두 장점과 단점이 있습니다.큰 상태 머신은 매우 쉽게 지저분해지고 복잡해집니다.그러나 두 번째 경우에도 모든 상태를 일관되게 유지하는 것은 쉽지 않으며 많은 함수에는 전역 상태와 하위 상태 모두에 대한 정보가 필요합니다.

다음과 같이 여러 병렬 상태를 처리해야 하는 복잡한 코드는 피하고 싶습니다.

if ((global_state == STATE1) &&
    (sub_state_1 == STATE1_DO_TRANSITION_TO_STATE2))
{
    ...
    if (transition_xy_done(...))
    {
        global_state = STATE2;
        sub_state_1 = STATE1_NOT_ACTIVE;
        sub_state_2 = STATE2_NORMAL;
    }
}

이러한 문제에 대한 일반적인 최선의 접근 방식은 무엇입니까?여러 개의 작고 중첩된 상태 머신(많은 유효하지 않은 조합 포함), 하나의 큰 상태 머신 또는 기타 무엇입니까?

도움이 되었습니까?

해결책

먼저, 무슨 일이 일어나고 있는지 인식하고 이러한 상태를 명시적으로 표시한 것에 대해 칭찬하고 싶습니다(실제로는 실제로 동작에 따른 전환이 아니라 모델의 추가 상태이기 때문입니다).(피하고 싶은) 마지막 예와 같은 상태 기계를 너무 자주 봅니다.이벤트 핸들러 내부에 '추가' 상태 변수에 대한 테스트가 있는 경우 이는 상태 머신에 디자인에 실제로 적용한 상태가 더 많이 있다는 신호입니다. 이러한 상태는 기존 상태의 이벤트에 끼어드는 것이 아니라 디자인에 반영됩니다. 전역 변수에 인코딩된 추가 '상태'에 대한 스파게티 코딩 검사가 포함된 핸들러입니다.

계층적 상태 머신(HSM)을 모델링하는 C++용 프레임워크는 여러 가지가 있지만(중첩 상태 머신 개념과 비슷합니다), 제가 아는 바로는 C를 지원하는 유일한 프레임워크는 다음과 같습니다. 양자 프레임워크, 그리고 나는 그것을 구매하는 것이 아마도 상당한 수준의 헌신을 의미할 것이라고 생각합니다(즉, 아마도 단순한 변화가 아닐 것입니다).그러나 이 가능성을 살펴보고 싶다면 Samek는 많은 기사를 썼습니다(그리고 책) C에서 HSM을 지원하는 방법에 대해 설명합니다.

그러나 HSM 모델의 보다 정교한 부분이 필요하지 않은 경우(예: '가장 안쪽' 상태에서 처리되지 않는 이벤트가 버블링되어 상위 상태에서 처리될 수 있음) 전체 상태 계층 구조), 상위 상태가 시작/종료될 때 시작 및 중지되는 완전히 독립적인 상태 머신과 마찬가지로 중첩된 상태 머신을 지원하는 것은 매우 쉽습니다.

큰 상태 머신 모델은 아마도 구현하기가 조금 더 쉬울 것입니다(기존 프레임워크에 상태가 몇 개 더 있을 뿐입니다).현재 상태 머신 모드에 상태를 추가해도 모델이 너무 복잡해지지 않는다면 그대로 사용하는 것이 좋습니다.

즉, 귀하에게 가장 적합한 것이 무엇인지 확인하십시오. 모델 소프트웨어에서 상태 머신을 구현하는 방법을 구동합니다.

다른 팁

많은 소규모 주 머신은 특히 무엇이든 재 설계 해야하는 경우 더 많은 코드 유연성을 제공 할 것입니다. 그런 다음 다른 중첩 상태 기계를 변경하지 않고도 중첩 상태 기계를 변경할 수 있어야합니다.

더 큰 전환 테이블을 사용하면 테이블을 메모리에 현명하게 배치한다고 가정하기 때문에 더 긴 조회가 발생하지 않아야합니다. 무엇이든, 소규모 상태 머신이 그들 사이에서 깨끗하게 전환하기 위해 필요한 추가 단계가 필요하지 않기 때문에 실제로 큰 기계에서 약간 더 빠른 속도를 얻을 수 있어야합니다. 그러나이 방법의 복잡성이 추가되면 다음을 제안 할 것입니다. 중첩 된 상태 머신을 사용한 설계를 제안한 다음 모든 것이 작동하면 약간의 속도 부스트를 얻기 위해 필요한 경우 단일 상태 머신으로 리팩터를 리팩토링하십시오.

당신이 언급했듯이, 큰 상태 기계는 지저분 해져서 유지하기가 매우 어렵습니다. 몇몇 작은 SM은 항상 이해하고 유지하기가 더 쉽습니다.

큰 SM- 더 큰 전환 테이블의 또 다른 단점이므로 조회는 더 오래 걸립니다.

나는 하나의 일반적인 접근법이 있다고 생각하지 않습니다. 다른 사람들이 말했듯이, 그것은 당신이하려는 일에 달려 있습니다.

광범위하게 말하면, 나는 당신이 물건을 단순화하려고 할 때 더 많은 상태를 추가 할뿐만 아니라 복잡성을 추가 할뿐만 아니라 큰 상태를 추가 할뿐만 아니라 큰 상태를 추가 할뿐만 아니라, 이제 두 가지 상태 변수를 추적 할 수 있으므로, 나는 더 큰 기계 내부에 작은 상태 기계를 중첩하지 않을 것입니다.

특히, "내부"상태 변수는 "외부"상태 기계에서 상태를 가로 질러 올바르게 초기화되어야합니다. 예를 들어, 버그로 인해 내부 상태 기계의 상태 변수를 재설정하지 못하는 외부 상태 머신에 전환이있는 경우 어떻게해야합니까?

이것에 대한 한 가지 예외는 모든 내부 상태 기계가 같은 일을하는 곳입니다. 데이터를 매개 변수화 할 수 있다면 (예 : 배열을 사용하여) 내부 상태 머신의 단일 구현을 가질 수 있으며 외부 상태 머신을 카운터 또는 이와 유사한 것으로 바꿀 수 있습니다.

단순한 예를 제시하려면 :

#define MyDataSIZE 10

void UpdateStateMachine(void)
{
    static enum {BeginSTATE, DoStuffSTATE, EndSTATE} State = BeginSTATE;
    static unsigned int Counter = 0;
    static unsigned int MyData[MyDataSIZE];

    switch(State)
    {
        default:
        case BeginSTATE:
            /* Some code */
            if(/* Some condition*/)
                {State = DoStuffSTATE;}
            break;
        case DoStuffSTATE:
            /* Some actions on MyData[Counter] */
            if(/* Some condition*/)
                {State = EndSTATE;}
            break;
        case EndSTATE:
            /* Some code */
            if(/* Some condition*/)
            {
                Counter++;
                if(Counter >= MyDataSIZE)
                    {Counter = 0;}
                State = BeginSTATE;
            } /* if */
            break;
    } /* switch */
} /* UpdateStateMachine() */

당신은 왜 사용하지 않습니까? 상태 패턴?

단일 기계가 큰 상태 기계 상태 중 하나에만있을 수 있다고 가정하면 더 큰 상태 머신에 투표합니다. 논리적으로 있어야합니다.

하나의 큰 기계를 사용하면 환경의 특성을 사용하여 두 상태가 동시에 존재하는 상태를 방지하여 프로그램을보다 안전하고 읽기 쉬운 상태로 만듭니다.

또한 하나의 큰 상태 머신은 다른 프로그래머가 단일 장소 (즉, 큰 그림을 얻음)를 보면서 모든 주를 쉽게 이해할 수 있다는 이점이 있습니다. 그런 다음 각 하위 부문을보아야합니다.

또한 여러 주 머신과의 협력을 제안했듯이 각 주에 대해 두 개 이상의 테스트를 수행하는 더 많은 매개 변수를 보내도록 강요합니다.

미래의 기대에 관해서는 나는 신자입니다 야그니.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top