ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 상태기계와 코루틴 프레임
    Programming🧑‍💻/Cpp 2025. 2. 14. 22:40

    코루틴이란?

    일반적인 함수의 경우 한번 호출되면 완료될때까지 실행되지만 

    코루틴은 실행 중간에 중단되었다가 나중에 중단됨 지점부터 다시 재개될 수 있는 함수입니다. 

    상태기계 (State Machine)

    상태기계는 코루틴이 어떻게 함수의 실행을 중단했다가 다시 재개할 수 있는지를 설명하는 핵심 매커니즘입니다. 

    컴파일러는 코루틴 함수를 상태기계로 변화하는 과정을 거칩니다. 

     

    예를 들어, 다음과 같은 코루틴이 있다고 가정했을 때, 

    task<int> example_coroutine() {
        std::cout << "시작" << std::endl;
        co_await first_operation();
        std::cout << "중간" << std::endl;
        co_await second_operation();
        std::cout << "끝" << std::endl;
        co_return 42;
    }

    컴파일러는 이 코드를 내부적으로 다음과 같은 상태들을 가진 상태 기계로 변환합니다. 

    // 컴파일러가 생성하는 내부적인 상태 기계의 의사 코드
    class ExampleCoroutineStateMachine {
    
        // 해당 코루틴이 가질 수 있는 상태 종류 정의 
        enum class State {
            Start = 0,          // 초기 상태
            AfterFirst = 1,     // first_operation 완료 후
            AfterSecond = 2,    // second_operation 완료 후
            Completed = 3       // 코루틴 완료
        };
    	
        // 현재 코루틴의 상태 
        State current_state = State::Start;
        
        // 상태에 따라 코루틴 재실행시 상태 설정 및 실행 위치 조정 
        void resume() {
            switch (current_state) {
                case State::Start:
                    std::cout << "시작" << std::endl;
                    first_operation();
                    current_state = State::AfterFirst;
                    break;
                    
                case State::AfterFirst:
                    std::cout << "중간" << std::endl;
                    second_operation();
                    current_state = State::AfterSecond;
                    break;
                    
                case State::AfterSecond:
                    std::cout << "끝" << std::endl;
                    result = 42;
                    current_state = State::Completed;
                    break;
            }
        }
        // 코루틴 완료 값 
        int result;
    };

     

    코루틴 프레임 ( Coroutine Frame)

    코루틴 프레임은 상태 기계가 중단, 재개를 거치며 실행될 때 필요로 하는 모든 데이터를 저장하는 메모리 구조 입니다. 이는 힙에 할당되며 다음과 같은 구조를 가집니다. 

    예제를 통해 이 구조가 어떻게 사용되는 살펴보면 

    task<int> calculate_sum(int start, int end) {
        int sum = 0;
        int current = start;
        
        while (current < end) {
            sum += current;
            current++;
            
            if (current % 1000 == 0) {
                co_await yield_point();  // 중단점
            }
        }
        
        co_return sum;
    }

    이 코드의 코투린 프레임은 다음과 같이 구성될 수 있습니다. 

    // 이 코드의 코루틴 프레임 구조
    struct CalculateSumFrame {
        // Promise 객체 - 결과값 관리
        promise_type<int> promise;
        
        // 매개변수 복사
        int start;
        int end;
        
        // 지역 변수들
        struct {
            int sum;
            int current;
        } locals;
        
        // 현재 상태
        enum class State {
            Initial,
            Yielded,
            Completed
        } current_state;
    };

    코루틴이 힙에 할당되는 이유는 아래와 같습니다. 

    • 수명 관리: 코루틴 프레임은 코루틴보다 오래 살아남을 수 있어야 합니다. 코루틴이 중단되어 콜 스택에서 해제되어도 프레임은 메모리에 유지되어야만 이후 다시 이를 참조하여 작업을 이어서 수행할 수 있기 때문입니다. 
    • 공유 가능성: 여러 실행 컨텍스트가 같은 코루틴 프레임에 접근할 수 있습니다.

     

    마지막으로 전체 내용을 정리하면

    • 상태 기계코루틴의 실행 로직을 관리합니다 (무엇을 실행할지)
    • 코루틴 프레임실행에 필요한 데이터를 관리합니다 (실행에 필요한 정보)
    • 두 요소가 함께 작동하여 코루틴의 중단과 재개를 가능하게 합니다

    이러한 구조 덕분에 코루틴은 실행 중간에 중단되었어도 나중에 정확히 같은 지점에 모든 상태를 유지한 채로 재개될 수 있습니다. 

    댓글

Designed by Tistory.