C++에서 RxCpp를 사용한 반응형 프로그래밍 기초

RxCpp를 활용한 반응형 프로그래밍은 C++에서 이벤트 기반 프로그래밍을 더욱 효과적으로 구현할 수 있도록 도와줍니다. 기존의 명령형 프로그래밍 방식은 상태 변화를 직접 관리해야 하는 반면, 반응형 프로그래밍은 데이터 흐름을 중심으로 이벤트를 처리하여 보다 직관적이고 유지보수가 쉬운 코드를 작성할 수 있습니다.

RxCpp는 ReactiveX(Rx) 패턴을 C++에서 사용할 수 있도록 설계된 라이브러리로, 이벤트 스트림을 효율적으로 관리하는 다양한 기능을 제공합니다. 이를 활용하면 데이터 변환, 필터링, 병합, 비동기 이벤트 처리를 간결한 코드로 표현할 수 있으며, 멀티스레드 환경에서도 안전한 이벤트 처리가 가능합니다.

본 기사에서는 반응형 프로그래밍의 기본 개념부터 시작하여, RxCpp의 주요 기능과 설치 방법을 다루고, 기본적인 코드 예제와 멀티스레딩 및 GUI 이벤트 처리와 같은 실전 응용 방법을 소개합니다. RxCpp를 활용하여 C++에서 보다 유연하고 확장성 있는 애플리케이션을 개발하는 방법을 함께 알아보겠습니다.

목차
  1. 반응형 프로그래밍이란?
    1. 기존 명령형 프로그래밍과의 차이점
    2. 반응형 프로그래밍의 특징
    3. 반응형 프로그래밍의 활용 사례
  2. RxCpp란 무엇인가?
    1. RxCpp의 주요 특징
    2. RxCpp가 필요한 이유
    3. RxCpp의 기본 개념
    4. RxCpp의 간단한 예제
  3. RxCpp 설치 및 환경 설정
    1. RxCpp 설치 방법
    2. RxCpp를 C++ 프로젝트에서 사용하는 방법
    3. CMake를 이용한 프로젝트 구성
    4. 환경 설정 후 실행 테스트
  4. RxCpp의 주요 개념과 연산자
    1. RxCpp의 주요 개념
    2. RxCpp의 주요 연산자
    3. RxCpp 연산자의 장점
  5. 기본적인 RxCpp 코드 예제
    1. 1. 기본적인 Observable 생성 및 구독
    2. 2. 데이터 변환 (map 연산자 사용)
    3. 3. 특정 조건을 만족하는 데이터만 필터링 (filter 연산자 사용)
    4. 4. 여러 Observable 병합 (merge 연산자 사용)
    5. 5. 비동기 데이터 스트림 생성 (interval 연산자 사용)
    6. RxCpp 예제 정리
  6. RxCpp를 활용한 비동기 이벤트 처리
    1. 1. 비동기 데이터 스트림 생성
    2. 2. 비동기적으로 실행되는 Observable 만들기
    3. 3. subscribe_on()과 observe_on()을 활용한 스레드 전환
    4. 4. 네트워크 요청을 비동기적으로 처리
    5. RxCpp를 활용한 비동기 이벤트 처리 정리
  7. RxCpp와 멀티스레딩
    1. 1. RxCpp에서 멀티스레드를 다루는 방법
    2. 2. 멀티스레드에서 Observable 실행
    3. 3. 백그라운드에서 실행하고 메인 스레드에서 결과 받기
    4. 4. 멀티스레딩을 활용한 이벤트 스트림 처리
    5. RxCpp와 멀티스레딩 정리
  8. 실전 응용: RxCpp를 활용한 GUI 이벤트 처리
    1. 1. RxCpp와 Qt 연동을 위한 준비
    2. 2. Qt 버튼 클릭 이벤트를 RxCpp로 처리
    3. 3. 텍스트 입력 이벤트를 RxCpp로 처리
    4. 4. 버튼 클릭을 일정 횟수 이상 감지하여 처리
    5. 5. GUI 이벤트와 비동기 네트워크 요청 결합
    6. RxCpp를 활용한 GUI 이벤트 처리 정리
  9. 요약
    1. 주요 내용 요약
    2. RxCpp 활용의 장점

반응형 프로그래밍이란?


반응형 프로그래밍(Reactve Programming, RP)은 데이터 흐름과 이벤트 전파를 중심으로 동작하는 프로그래밍 패러다임입니다. 기존의 명령형 프로그래밍에서는 프로그램이 특정 명령을 수행할 때마다 상태를 직접 변경하고 관리해야 하지만, 반응형 프로그래밍은 데이터의 변화를 자동으로 감지하고 이에 따라 적절한 처리를 수행하는 방식으로 동작합니다.

기존 명령형 프로그래밍과의 차이점


명령형 프로그래밍과 반응형 프로그래밍의 가장 큰 차이점은 제어 흐름 방식입니다.

  • 명령형 프로그래밍: 명령어를 순차적으로 실행하며 프로그램의 상태를 변경하는 방식입니다. 상태 변화를 직접 코드에서 관리해야 하므로 복잡한 이벤트 처리나 비동기 작업에서 코드가 복잡해질 수 있습니다.
  • 반응형 프로그래밍: 데이터가 변경되었을 때 자동으로 연관된 연산이 수행됩니다. 즉, 이벤트를 기반으로 데이터 흐름을 구성하며, 비동기적이고 선언적인 방식으로 동작합니다.

반응형 프로그래밍의 특징

  1. 이벤트 중심(Event-driven): 이벤트가 발생하면 해당 이벤트를 자동으로 감지하고 반응합니다.
  2. 데이터 스트림 기반: 시간에 따라 변화하는 데이터를 스트림 형태로 다룹니다.
  3. 선언적 코드(Declarative Code): 상태 변경을 직접 명령하지 않고, 데이터의 흐름을 정의하여 코드를 간결하고 유지보수하기 쉽게 만듭니다.
  4. 비동기 처리: 비동기 작업을 효율적으로 처리하며, 멀티스레딩 환경에서도 안전한 이벤트 처리가 가능합니다.

반응형 프로그래밍의 활용 사례


반응형 프로그래밍은 다양한 분야에서 활용됩니다.

  • GUI 애플리케이션: 사용자 입력(클릭, 키 입력 등)에 반응하여 UI를 자동으로 업데이트
  • 비동기 데이터 처리: 네트워크 요청, 파일 입출력 등의 작업을 이벤트 기반으로 수행
  • 실시간 데이터 스트림 처리: 금융 데이터 분석, 센서 데이터 처리 등에서 활용
  • 멀티스레드 프로그래밍: 동시성과 병렬성을 효율적으로 처리

C++에서는 RxCpp를 활용하여 반응형 프로그래밍을 구현할 수 있으며, 이를 통해 보다 유연하고 유지보수성이 높은 애플리케이션을 개발할 수 있습니다. 다음 섹션에서는 RxCpp에 대해 자세히 알아보겠습니다.

RxCpp란 무엇인가?


RxCpp는 ReactiveX(Rx) 패턴을 C++에서 구현한 라이브러리로, 이벤트 기반 프로그래밍을 쉽게 구현할 수 있도록 돕습니다. ReactiveX는 데이터 스트림과 비동기 이벤트를 효과적으로 처리하기 위한 라이브러리 모음이며, Java의 RxJava, JavaScript의 RxJS, Python의 RxPY 등 다양한 언어에서 지원됩니다.

RxCpp는 이러한 ReactiveX 패턴을 C++ 환경에서 사용할 수 있도록 제공하며, 기존 명령형 프로그래밍보다 간결하고 효율적인 이벤트 처리 및 비동기 코드 작성을 가능하게 합니다.

RxCpp의 주요 특징

  1. 이벤트 스트림 기반 처리: 데이터가 흘러가는 스트림을 정의하고 이를 조작하는 방식으로 프로그래밍합니다.
  2. 비동기 이벤트 처리: 네트워크 요청, 파일 입출력, UI 이벤트 등을 자연스럽게 비동기적으로 처리할 수 있습니다.
  3. 선언적 프로그래밍 방식: map(), filter(), merge() 등의 연산자를 활용해 명확하고 간결한 코드를 작성할 수 있습니다.
  4. 멀티스레드 지원: observe_on()subscribe_on()을 활용하여 멀티스레드 환경에서도 안전하게 데이터 흐름을 제어할 수 있습니다.
  5. C++ 표준 라이브러리와의 호환성: std::function, std::thread, std::vector 등을 활용하여 기존 C++ 코드와 유기적으로 통합할 수 있습니다.

RxCpp가 필요한 이유


전통적인 C++에서는 이벤트를 처리하기 위해 콜백(Callback) 함수를 사용하거나, Observer 패턴을 직접 구현해야 했습니다. 하지만 이러한 방식은 코드가 복잡해지고, 여러 개의 이벤트를 조합하거나 체이닝하는 것이 어렵습니다.

RxCpp를 사용하면 비동기 작업을 더 선언적으로 표현하고, 데이터 흐름을 단순하게 구성할 수 있습니다.

예를 들어, 여러 개의 UI 버튼 클릭 이벤트를 병합하고 필터링하려면 기존 방식에서는 이벤트 리스너를 직접 관리해야 하지만, RxCpp에서는 단순한 연산자로 쉽게 처리할 수 있습니다.

RxCpp의 기본 개념


RxCpp에서 가장 중요한 개념은 다음과 같습니다.

  • Observable: 데이터 스트림을 나타내며, 시간에 따라 변하는 값을 발행(emit)합니다.
  • Observer: Observable을 구독(subscribe)하여 데이터를 받아 처리하는 역할을 합니다.
  • Subscription: Observable과 Observer 간의 연결을 관리하며, 필요할 경우 구독을 취소할 수 있습니다.
  • Operators(연산자): map(), filter(), merge(), combineLatest() 등의 연산자를 활용하여 데이터 변환 및 조작을 수행합니다.

RxCpp의 간단한 예제


다음은 RxCpp를 사용하여 숫자 스트림을 생성하고, 필터링 후 출력하는 코드입니다.

#include <rxcpp/rx.hpp>
#include <iostream>

int main() {
    auto values = rxcpp::observable<>::range(1, 10) // 1부터 10까지의 숫자 생성
        .filter([](int x) { return x % 2 == 0; }) // 짝수만 필터링
        .map([](int x) { return x * 10; }); // 각 숫자를 10배 증가

    values.subscribe([](int v) { std::cout << v << " "; }); // 결과 출력
}

출력 결과

20 40 60 80 100

위 코드에서는 RxCpp의 연산자(filter, map) 를 사용하여 데이터를 조작하고, subscribe()를 통해 데이터를 소비(consume)하는 방식으로 동작합니다.

다음 섹션에서는 RxCpp를 C++ 프로젝트에서 사용하기 위해 설치하고 환경을 설정하는 방법을 설명하겠습니다.

RxCpp 설치 및 환경 설정


RxCpp를 C++ 프로젝트에서 사용하려면 라이브러리를 설치하고 환경을 설정해야 합니다. RxCpp는 헤더 파일 기반 라이브러리이므로 빌드 과정에서 별도의 바이너리 파일을 생성할 필요 없이 간단하게 포함하여 사용할 수 있습니다.

RxCpp 설치 방법


RxCpp를 설치하는 방법은 크게 패키지 매니저를 사용하는 방법소스 코드에서 직접 빌드하는 방법 두 가지가 있습니다.

1. vcpkg를 이용한 설치 (권장)


vcpkg는 C++ 라이브러리를 쉽게 설치할 수 있는 패키지 매니저입니다.

  1. vcpkg가 설치되지 않았다면, 먼저 vcpkg를 다운로드하고 빌드합니다.
   git clone https://github.com/microsoft/vcpkg.git
   cd vcpkg
   ./bootstrap-vcpkg.sh  # (Linux/macOS)
   .\bootstrap-vcpkg.bat # (Windows)
  1. RxCpp 라이브러리를 설치합니다.
   ./vcpkg install rxcpp
  1. CMake 프로젝트에서 RxCpp를 사용하려면 다음을 CMakeLists.txt에 추가합니다.
   find_package(RxCpp CONFIG REQUIRED)
   target_link_libraries(MyProject PRIVATE RxCpp)
  1. vcpkg를 CMake에 통합하여 빌드합니다.
   cmake -DCMAKE_TOOLCHAIN_FILE=path/to/vcpkg/scripts/buildsystems/vcpkg.cmake ..
   cmake --build .

2. Conan을 이용한 설치


Conan은 또 다른 C++ 패키지 매니저로, RxCpp를 쉽게 관리할 수 있습니다.

  1. Conan을 설치합니다.
   pip install conan
  1. 프로젝트에서 conanfile.txt를 작성합니다.
   [requires]
   rxcpp/4.1.0

[generators]

cmake

  1. Conan을 이용해 패키지를 설치하고 CMake와 연동합니다.
   conan install . --build=missing

3. 소스 코드에서 직접 빌드


RxCpp는 헤더 파일 기반 라이브러리이므로, 단순히 소스 코드를 다운로드하여 프로젝트에 추가하는 것도 가능합니다.

  1. GitHub에서 RxCpp 소스를 다운로드합니다.
   git clone https://github.com/ReactiveX/RxCpp.git
  1. RxCpp의 Rx/v2/src 폴더를 프로젝트의 헤더 포함 경로에 추가합니다.

RxCpp를 C++ 프로젝트에서 사용하는 방법


RxCpp를 프로젝트에서 사용하려면 헤더 파일을 포함하고, RxCpp 네임스페이스를 사용하면 됩니다.

#include <rxcpp/rx.hpp>
#include <iostream>

int main() {
    auto values = rxcpp::observable<>::range(1, 5); // 1부터 5까지의 숫자 생성
    values.subscribe([](int v) { std::cout << v << " "; });
}

CMake를 이용한 프로젝트 구성


RxCpp를 CMake 프로젝트에서 사용할 경우 CMakeLists.txt 파일에 다음을 추가합니다.

cmake_minimum_required(VERSION 3.10)
project(RxCppExample)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)

find_package(RxCpp REQUIRED)

add_executable(RxCppExample main.cpp)
target_link_libraries(RxCppExample PRIVATE RxCpp)

환경 설정 후 실행 테스트


RxCpp가 올바르게 설치되었는지 확인하려면 다음 명령어로 프로젝트를 빌드하고 실행할 수 있습니다.

mkdir build && cd build
cmake ..
cmake --build .
./RxCppExample  # 실행

RxCpp를 성공적으로 설치하고 환경을 설정하면, 반응형 프로그래밍을 활용하여 비동기 이벤트 처리 및 스트림 조작을 할 수 있습니다. 다음 섹션에서는 RxCpp의 핵심 개념과 주요 연산자에 대해 설명하겠습니다.

RxCpp의 주요 개념과 연산자


RxCpp는 반응형 프로그래밍을 C++에서 구현하기 위한 라이브러리로, 이벤트 스트림을 기반으로 데이터를 처리하는 방식을 제공합니다. 이를 이해하기 위해서는 Observable(관찰 대상), Observer(관찰자), Subscription(구독) 등의 핵심 개념과 Rx 연산자를 익혀야 합니다.

RxCpp의 주요 개념

1. Observable(관찰 대상)


Observable은 데이터를 발행하는 객체로, 이벤트 스트림을 나타냅니다.

auto source = rxcpp::observable<>::range(1, 5);

위 코드는 1부터 5까지의 숫자를 생성하는 Observable을 만듭니다.

2. Observer(관찰자)


ObserverObservable이 발행하는 데이터를 받아 처리하는 객체입니다. subscribe() 함수를 통해 Observer를 등록할 수 있습니다.

source.subscribe([](int v) { std::cout << v << " "; });

출력:

1 2 3 4 5

이처럼 ObserverObservable에서 생성한 데이터를 지속적으로 감지하고 반응합니다.

3. Subscription(구독)


ObservableObserver가 연결되면 Subscription이 생성되며, 필요할 경우 unsubscribe()를 호출하여 구독을 중단할 수 있습니다.

RxCpp의 주요 연산자


RxCpp는 데이터 흐름을 조작할 수 있는 다양한 연산자를 제공합니다. 주요 연산자는 다음과 같습니다.

1. map(): 데이터 변환


map() 연산자는 Observable의 데이터를 변환하는 데 사용됩니다.

auto values = rxcpp::observable<>::range(1, 5)
    .map([](int x) { return x * 10; });

values.subscribe([](int v) { std::cout << v << " "; });

출력:

10 20 30 40 50

2. filter(): 조건에 맞는 데이터만 선택


filter() 연산자는 특정 조건을 만족하는 데이터만 통과시킵니다.

auto values = rxcpp::observable<>::range(1, 10)
    .filter([](int x) { return x % 2 == 0; });

values.subscribe([](int v) { std::cout << v << " "; });

출력:

2 4 6 8 10

3. merge(): 여러 Observable을 병합


merge() 연산자는 여러 개의 Observable을 하나의 스트림으로 합칩니다.

auto obs1 = rxcpp::observable<>::just(1, 2, 3);
auto obs2 = rxcpp::observable<>::just(4, 5, 6);
auto merged = obs1.merge(obs2);

merged.subscribe([](int v) { std::cout << v << " "; });

출력:

1 2 3 4 5 6

4. combineLatest(): 여러 개의 Observable을 결합


combineLatest()는 여러 개의 Observable에서 가장 최신 데이터를 조합합니다.

auto obs1 = rxcpp::observable<>::interval(std::chrono::milliseconds(500)).take(3);
auto obs2 = rxcpp::observable<>::interval(std::chrono::milliseconds(300)).take(3);

obs1.combine_latest([](int a, int b) { return a + b; }, obs2)
    .subscribe([](int v) { std::cout << v << " "; });

출력 예시(비동기 처리로 값이 달라질 수 있음):

1 3 4 5 ...

5. distinct(): 중복 데이터 제거


distinct()는 중복된 데이터를 제거하고 유일한 값만 방출합니다.

auto values = rxcpp::observable<>::just(1, 2, 2, 3, 4, 4, 5)
    .distinct();

values.subscribe([](int v) { std::cout << v << " "; });

출력:

1 2 3 4 5

RxCpp 연산자의 장점


RxCpp의 연산자를 활용하면 기존 명령형 프로그래밍보다 더 직관적이고 간결하게 데이터 변환 및 필터링 작업을 수행할 수 있습니다.

  • 코드의 가독성 향상: 데이터를 변환, 필터링, 결합하는 과정을 명확하게 표현 가능
  • 비동기 프로그래밍 용이: 콜백 지옥(callback hell)을 방지하고, 선언적으로 비동기 코드 작성 가능
  • 멀티스레드 환경 지원: observe_on(), subscribe_on() 연산자를 활용하여 스레드 간 이벤트 처리 가능

RxCpp를 활용하면 복잡한 이벤트 기반 시스템을 보다 효율적으로 구성할 수 있습니다. 다음 섹션에서는 RxCpp를 활용한 기본적인 코드 예제를 살펴보겠습니다.

기본적인 RxCpp 코드 예제


RxCpp를 사용하여 반응형 프로그래밍을 구현하는 방법을 이해하기 위해 간단한 코드 예제를 살펴보겠습니다. 여기에서는 Observable을 생성하고 데이터를 변환 및 필터링하여 Observer가 구독하는 방식을 설명합니다.

1. 기본적인 Observable 생성 및 구독


다음 예제는 Observable을 생성하고, 이를 Observer가 구독하여 데이터를 처리하는 기본적인 흐름을 보여줍니다.

#include <rxcpp/rx.hpp>
#include <iostream>

int main() {
    // 1부터 5까지의 숫자를 발행하는 Observable 생성
    auto source = rxcpp::observable<>::range(1, 5);

    // 데이터를 구독하여 출력
    source.subscribe(
        [](int v) { std::cout << "Received: " << v << std::endl; }, // onNext
        []() { std::cout << "Stream completed!" << std::endl; } // onCompleted
    );

    return 0;
}

출력 결과:

Received: 1  
Received: 2  
Received: 3  
Received: 4  
Received: 5  
Stream completed!

이 코드에서 range(1, 5)1부터 5까지의 숫자를 발행하는 Observable을 생성하며, subscribe() 함수를 통해 Observer가 데이터를 받습니다.


2. 데이터 변환 (map 연산자 사용)


다음 예제는 map() 연산자를 사용하여 각 데이터에 변환을 적용하는 방식입니다.

#include <rxcpp/rx.hpp>
#include <iostream>

int main() {
    auto source = rxcpp::observable<>::range(1, 5)
        .map([](int x) { return x * 10; }); // 각 요소를 10배 증가

    source.subscribe([](int v) { std::cout << v << " "; });

    return 0;
}

출력 결과:

10 20 30 40 50

map()을 사용하여 각 요소를 변환할 수 있음을 확인할 수 있습니다.


3. 특정 조건을 만족하는 데이터만 필터링 (filter 연산자 사용)


다음 예제는 filter() 연산자를 사용하여 특정 조건을 만족하는 값만 선택하는 방식입니다.

#include <rxcpp/rx.hpp>
#include <iostream>

int main() {
    auto source = rxcpp::observable<>::range(1, 10)
        .filter([](int x) { return x % 2 == 0; }); // 짝수만 필터링

    source.subscribe([](int v) { std::cout << v << " "; });

    return 0;
}

출력 결과:

2 4 6 8 10

filter() 연산자를 사용하면 원하는 조건에 맞는 데이터만 선택적으로 처리할 수 있습니다.


4. 여러 Observable 병합 (merge 연산자 사용)


여러 개의 Observable을 병합하는 예제입니다.

#include <rxcpp/rx.hpp>
#include <iostream>

int main() {
    auto obs1 = rxcpp::observable<>::just(1, 3, 5);
    auto obs2 = rxcpp::observable<>::just(2, 4, 6);
    auto merged = obs1.merge(obs2);

    merged.subscribe([](int v) { std::cout << v << " "; });

    return 0;
}

출력 결과 (실행 환경에 따라 순서가 다를 수 있음):

1 2 3 4 5 6

merge()를 사용하면 여러 개의 Observable을 하나의 스트림으로 결합할 수 있습니다.


5. 비동기 데이터 스트림 생성 (interval 연산자 사용)


비동기적으로 데이터를 생성하는 interval() 연산자를 활용하여 주기적인 이벤트를 처리하는 방식입니다.

#include <rxcpp/rx.hpp>
#include <iostream>
#include <chrono>
#include <thread>

int main() {
    auto source = rxcpp::observable<>::interval(std::chrono::milliseconds(500))
        .take(5); // 500ms마다 데이터 생성, 최대 5개

    source.subscribe(
        [](int v) { std::cout << "Tick: " << v << std::endl; },
        []() { std::cout << "Completed!" << std::endl; }
    );

    std::this_thread::sleep_for(std::chrono::seconds(3)); // 프로그램 종료 방지
    return 0;
}

출력 예시:

Tick: 0  
Tick: 1  
Tick: 2  
Tick: 3  
Tick: 4  
Completed!

이처럼 interval()을 사용하면 비동기적으로 주기적인 이벤트를 생성할 수 있습니다.


RxCpp 예제 정리


위 예제들은 RxCpp의 기본 개념을 활용하여 데이터 흐름을 조작하고, 비동기적으로 이벤트를 처리하는 방법을 보여줍니다.

연산자기능예제
map()데이터를 변환x * 10
filter()특정 조건을 만족하는 데이터 선택짝수 필터링
merge()여러 Observable 결합obs1.merge(obs2)
interval()비동기적으로 일정 시간마다 이벤트 생성500ms 간격 이벤트

RxCpp를 사용하면 기존 C++ 코드보다 더 직관적이고 선언적인 방식으로 데이터 스트림을 관리할 수 있습니다. 다음 섹션에서는 RxCpp를 활용하여 비동기 이벤트를 처리하는 방법을 다뤄보겠습니다.

RxCpp를 활용한 비동기 이벤트 처리


RxCpp는 비동기 이벤트 처리를 효과적으로 지원하며, 기존의 콜백 기반 비동기 프로그래밍보다 더 선언적이고 유지보수하기 쉬운 방식을 제공합니다. 이를 활용하면 네트워크 요청, 파일 입출력, 사용자 입력 이벤트 등의 비동기 작업을 더욱 간결하게 표현할 수 있습니다.

1. 비동기 데이터 스트림 생성


RxCpp에서 비동기적으로 이벤트를 생성하는 대표적인 방법은 interval()을 사용하는 것입니다.
아래 코드는 500ms마다 이벤트를 발생시키는 비동기 스트림을 생성합니다.

#include <rxcpp/rx.hpp>
#include <iostream>
#include <chrono>
#include <thread>

int main() {
    auto source = rxcpp::observable<>::interval(std::chrono::milliseconds(500))
        .take(5); // 500ms마다 데이터 생성, 최대 5개

    source.subscribe(
        [](int v) { std::cout << "Tick: " << v << std::endl; },
        []() { std::cout << "Completed!" << std::endl; }
    );

    std::this_thread::sleep_for(std::chrono::seconds(3)); // 프로그램 종료 방지
    return 0;
}

출력 예시:

Tick: 0  
Tick: 1  
Tick: 2  
Tick: 3  
Tick: 4  
Completed!

위 코드에서는 interval() 연산자를 사용하여 비동기적인 데이터 스트림을 생성하고, take(5)를 사용해 5개의 이벤트만 처리하도록 설정했습니다.


2. 비동기적으로 실행되는 Observable 만들기


RxCpp에서 rxcpp::observable<>::create()를 사용하면 사용자 정의 비동기 Observable을 만들 수 있습니다.
다음 예제는 백그라운드 스레드에서 실행되는 비동기 Observable을 생성하는 방법을 보여줍니다.

#include <rxcpp/rx.hpp>
#include <iostream>
#include <chrono>
#include <thread>

int main() {
    auto asyncObservable = rxcpp::observable<>::create<int>(
        [](rxcpp::subscriber<int> s) {
            std::thread([s]() mutable {
                for (int i = 0; i < 5; i++) {
                    std::this_thread::sleep_for(std::chrono::milliseconds(500));
                    s.on_next(i);
                }
                s.on_completed();
            }).detach();
        }
    );

    asyncObservable.subscribe(
        [](int v) { std::cout << "Received: " << v << std::endl; },
        []() { std::cout << "Stream Completed!" << std::endl; }
    );

    std::this_thread::sleep_for(std::chrono::seconds(3)); // 프로그램 종료 방지
    return 0;
}

출력 예시:

Received: 0  
Received: 1  
Received: 2  
Received: 3  
Received: 4  
Stream Completed!

이 코드에서 create()를 사용하여 별도의 스레드에서 실행되는 Observable을 만들었으며, on_next()를 호출하여 데이터를 전송하고, 마지막에 on_completed()를 호출하여 스트림을 종료합니다.


3. subscribe_on()과 observe_on()을 활용한 스레드 전환


RxCpp에서는 subscribe_on()observe_on()을 활용하여 비동기 작업을 특정 스레드에서 실행할 수 있습니다.

  • subscribe_on()Observable의 실행 스레드를 지정
  • observe_on()Observer가 데이터를 소비하는 스레드를 지정

아래 예제는 비동기적으로 실행한 후, 메인 스레드에서 결과를 수신하는 방법을 보여줍니다.

#include <rxcpp/rx.hpp>
#include <iostream>
#include <chrono>
#include <thread>

int main() {
    auto scheduler = rxcpp::observe_on_new_thread();

    auto source = rxcpp::observable<>::range(1, 5)
        .map([](int x) { return x * 10; }) // 데이터 변환
        .subscribe_on(scheduler)  // 별도 스레드에서 실행
        .observe_on(rxcpp::observe_on_event_loop()); // 메인 루프로 결과 전달

    source.subscribe(
        [](int v) { std::cout << "Received: " << v << " on thread " << std::this_thread::get_id() << std::endl; },
        []() { std::cout << "Completed on thread " << std::this_thread::get_id() << std::endl; }
    );

    std::this_thread::sleep_for(std::chrono::seconds(2)); // 프로그램 종료 방지
    return 0;
}

출력 예시 (스레드 ID는 실행 환경에 따라 다름):

Received: 10 on thread 12345  
Received: 20 on thread 12345  
Received: 30 on thread 12345  
Received: 40 on thread 12345  
Received: 50 on thread 12345  
Completed on thread 12345

이 예제에서는

  • subscribe_on(scheduler)를 사용하여 별도의 스레드에서 Observable을 실행
  • observe_on(rxcpp::observe_on_event_loop())를 사용하여 메인 이벤트 루프에서 결과를 수신하도록 설정했습니다.

4. 네트워크 요청을 비동기적으로 처리


RxCpp를 활용하면 네트워크 요청과 같은 비동기 작업을 선언적으로 처리할 수 있습니다.
다음 예제는 가상의 네트워크 요청을 시뮬레이션하는 방식입니다.

#include <rxcpp/rx.hpp>
#include <iostream>
#include <chrono>
#include <thread>

auto mockHttpRequest() {
    return rxcpp::observable<>::create<std::string>(
        [](rxcpp::subscriber<std::string> s) {
            std::thread([s]() mutable {
                std::this_thread::sleep_for(std::chrono::seconds(2)); // 네트워크 지연 시간 시뮬레이션
                s.on_next("Response: 200 OK");
                s.on_completed();
            }).detach();
        }
    );
}

int main() {
    std::cout << "Sending request..." << std::endl;

    auto request = mockHttpRequest()
        .subscribe_on(rxcpp::observe_on_new_thread()) // 네트워크 요청을 새로운 스레드에서 실행
        .observe_on(rxcpp::observe_on_event_loop());  // 메인 이벤트 루프에서 응답 수신

    request.subscribe(
        [](std::string response) { std::cout << response << std::endl; },
        []() { std::cout << "Request completed!" << std::endl; }
    );

    std::this_thread::sleep_for(std::chrono::seconds(3)); // 프로그램 종료 방지
    return 0;
}

출력 결과:

Sending request...
Response: 200 OK
Request completed!

이 예제에서는 mockHttpRequest()를 통해 가상의 네트워크 요청을 시뮬레이션하고, RxCpp의 비동기 스트림을 활용하여 데이터를 수신합니다.


RxCpp를 활용한 비동기 이벤트 처리 정리


RxCpp를 활용하면 기존의 콜백 기반 비동기 프로그래밍보다 더 직관적이고 유지보수하기 쉬운 코드를 작성할 수 있습니다.

기능RxCpp 연산자예제
일정 시간마다 이벤트 생성interval()500ms마다 이벤트 발생
사용자 정의 비동기 Observablecreate()별도 스레드에서 데이터 생성
스레드 전환subscribe_on(), observe_on()작업 실행 및 결과 처리 스레드 변경
네트워크 요청 처리create()비동기 요청 후 결과 수신

RxCpp를 사용하면 복잡한 이벤트 기반 프로그래밍, 네트워크 요청, 멀티스레드 환경을 보다 간결하게 구현할 수 있습니다.
다음 섹션에서는 RxCpp와 멀티스레딩을 활용한 고급 이벤트 처리 기법을 다루겠습니다.

RxCpp와 멀티스레딩


RxCpp는 멀티스레드 환경에서 이벤트 기반 프로그래밍을 안전하고 효율적으로 수행할 수 있도록 지원합니다.
멀티스레딩을 활용하면 백그라운드 작업을 실행하면서 메인 스레드에서 결과를 수신할 수 있으며,
이를 통해 네트워크 요청, 파일 입출력, 데이터 처리 등을 비동기적으로 수행할 수 있습니다.


1. RxCpp에서 멀티스레드를 다루는 방법


RxCpp는 멀티스레딩을 지원하기 위해 subscribe_on()observe_on() 연산자를 제공합니다.

  • subscribe_on(scheduler): Observable이 실행되는 스레드를 지정
  • observe_on(scheduler): Observer가 데이터를 소비하는 스레드를 지정

이를 활용하면 백그라운드 스레드에서 데이터를 생성하고, 메인 스레드에서 결과를 처리할 수 있습니다.


2. 멀티스레드에서 Observable 실행


다음 예제는 subscribe_on()을 사용하여 별도의 스레드에서 Observable을 실행하는 방법을 보여줍니다.

#include <rxcpp/rx.hpp>
#include <iostream>
#include <chrono>
#include <thread>

int main() {
    auto scheduler = rxcpp::observe_on_new_thread();

    auto source = rxcpp::observable<>::range(1, 5)
        .map([](int x) { return x * 10; }) // 데이터를 변환
        .subscribe_on(scheduler);  // 별도 스레드에서 실행

    source.subscribe(
        [](int v) { std::cout << "Received: " << v << " on thread " << std::this_thread::get_id() << std::endl; },
        []() { std::cout << "Completed on thread " << std::this_thread::get_id() << std::endl; }
    );

    std::this_thread::sleep_for(std::chrono::seconds(2)); // 프로그램 종료 방지
    return 0;
}

출력 예시 (스레드 ID는 실행 환경에 따라 다름):

Received: 10 on thread 12345  
Received: 20 on thread 12345  
Received: 30 on thread 12345  
Received: 40 on thread 12345  
Received: 50 on thread 12345  
Completed on thread 12345

설명:

  • subscribe_on(scheduler)을 사용하여 별도의 스레드에서 데이터가 생성됨
  • Observer는 동일한 스레드에서 데이터를 수신

3. 백그라운드에서 실행하고 메인 스레드에서 결과 받기


다음 예제는 observe_on()을 사용하여 백그라운드 스레드에서 데이터를 처리한 후, 메인 스레드에서 결과를 수신하는 방식입니다.

#include <rxcpp/rx.hpp>
#include <iostream>
#include <chrono>
#include <thread>

int main() {
    auto computation_thread = rxcpp::observe_on_new_thread();
    auto main_thread = rxcpp::observe_on_event_loop();

    auto source = rxcpp::observable<>::range(1, 5)
        .map([](int x) { 
            std::cout << "Processing: " << x << " on thread " << std::this_thread::get_id() << std::endl;
            return x * 10; 
        })
        .subscribe_on(computation_thread) // 백그라운드에서 실행
        .observe_on(main_thread);  // 메인 스레드에서 결과 처리

    source.subscribe(
        [](int v) { std::cout << "Received: " << v << " on thread " << std::this_thread::get_id() << std::endl; },
        []() { std::cout << "Completed on thread " << std::this_thread::get_id() << std::endl; }
    );

    std::this_thread::sleep_for(std::chrono::seconds(2)); // 프로그램 종료 방지
    return 0;
}

출력 예시:

Processing: 1 on thread 12345  
Processing: 2 on thread 12345  
Processing: 3 on thread 12345  
Processing: 4 on thread 12345  
Processing: 5 on thread 12345  
Received: 10 on thread 67890  
Received: 20 on thread 67890  
Received: 30 on thread 67890  
Received: 40 on thread 67890  
Received: 50 on thread 67890  
Completed on thread 67890

설명:

  • subscribe_on(computation_thread): 백그라운드에서 데이터 처리
  • observe_on(main_thread): 메인 스레드에서 최종 결과 수신

4. 멀티스레딩을 활용한 이벤트 스트림 처리


RxCpp를 활용하면 여러 개의 스레드를 사용하여 이벤트를 동시에 처리할 수도 있습니다.

#include <rxcpp/rx.hpp>
#include <iostream>
#include <chrono>
#include <thread>

int main() {
    auto source = rxcpp::observable<>::range(1, 10)
        .filter([](int x) { return x % 2 == 0; }) // 짝수만 선택
        .map([](int x) { return x * 10; }) // 변환
        .subscribe_on(rxcpp::observe_on_new_thread()) // 비동기 실행
        .observe_on(rxcpp::observe_on_event_loop()); // 메인 스레드에서 결과 수신

    source.subscribe(
        [](int v) { std::cout << "Processed: " << v << " on thread " << std::this_thread::get_id() << std::endl; },
        []() { std::cout << "Completed!" << std::endl; }
    );

    std::this_thread::sleep_for(std::chrono::seconds(2)); // 프로그램 종료 방지
    return 0;
}

출력 예시:

Processed: 20 on thread 12345  
Processed: 40 on thread 12345  
Processed: 60 on thread 12345  
Processed: 80 on thread 12345  
Processed: 100 on thread 12345  
Completed!

설명:

  • filter()map()을 사용하여 데이터 변환 및 필터링
  • 백그라운드에서 실행 후 메인 스레드에서 결과를 수신

RxCpp와 멀티스레딩 정리


RxCpp는 멀티스레드 환경에서도 안전하게 이벤트 스트림을 관리할 수 있도록 다양한 기능을 제공합니다.

기능RxCpp 연산자예제
비동기적으로 Observable 실행subscribe_on()백그라운드에서 데이터 생성
특정 스레드에서 Observer 실행observe_on()메인 스레드에서 결과 수신
병렬 데이터 처리여러 개의 Observable스레드 풀 활용
이벤트 기반 멀티스레딩interval(), create()이벤트 기반 비동기 처리

RxCpp를 활용하면 멀티스레드 환경에서도 안전하고 선언적인 방식으로 이벤트를 처리할 수 있습니다.
다음 섹션에서는 RxCpp를 GUI 이벤트 처리에 적용하는 방법을 살펴보겠습니다.

실전 응용: RxCpp를 활용한 GUI 이벤트 처리


RxCpp는 GUI 애플리케이션에서 이벤트 기반 프로그래밍을 구현하는 데 유용하게 사용할 수 있습니다.
GUI 프로그래밍에서는 버튼 클릭, 키 입력, 마우스 이벤트 등의 사용자 인터랙션을 처리해야 하며,
RxCpp를 활용하면 이벤트를 스트림으로 관리하고, 비동기적으로 처리할 수 있습니다.

이 섹션에서는 Qt 프레임워크와 RxCpp를 함께 사용하여 반응형 GUI 이벤트 처리를 구현하는 방법을 설명합니다.


1. RxCpp와 Qt 연동을 위한 준비


Qt 프레임워크는 GUI 프로그래밍을 위한 강력한 툴킷으로, 이벤트 기반 프로그래밍을 지원하는 시그널-슬롯(Signal-Slot) 메커니즘을 제공합니다.
RxCpp를 활용하면 Qt의 이벤트를 반응형 스트림으로 변환하여 처리할 수 있습니다.

설치 방법:

sudo apt install qtbase5-dev   # Ubuntu
brew install qt                # macOS

Qt 프로젝트에서 CMakeLists.txt에 Qt 및 RxCpp를 포함합니다.

find_package(Qt5 COMPONENTS Widgets REQUIRED)
find_package(RxCpp REQUIRED)

add_executable(MyApp main.cpp)
target_link_libraries(MyApp PRIVATE Qt5::Widgets RxCpp)

2. Qt 버튼 클릭 이벤트를 RxCpp로 처리


다음은 버튼 클릭 이벤트를 RxCpp의 Observable로 변환하고, 이를 통해 이벤트를 처리하는 예제입니다.

#include <QApplication>
#include <QPushButton>
#include <rxcpp/rx.hpp>
#include <iostream>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QPushButton button("Click Me");
    button.show();

    auto buttonClicks = rxcpp::observable<>::create<int>(
        [&button](rxcpp::subscriber<int> s) {
            QObject::connect(&button, &QPushButton::clicked, [&s]() {
                static int clickCount = 0;
                s.on_next(++clickCount); // 버튼 클릭 횟수 전송
            });
        });

    buttonClicks.subscribe([](int count) {
        std::cout << "Button clicked " << count << " times" << std::endl;
    });

    return app.exec();
}

출력 예시:

Button clicked 1 times  
Button clicked 2 times  
Button clicked 3 times  
...

설명:

  • create()를 사용하여 버튼 클릭 이벤트를 Observable로 변환
  • subscribe()를 통해 클릭 횟수를 감지하고 출력
  • Qt의 Signal-Slot을 RxCpp 스트림으로 변환하여 이벤트 기반 처리 가능

3. 텍스트 입력 이벤트를 RxCpp로 처리


다음은 QLineEdit 입력 필드를 RxCpp와 연동하여 사용자가 입력한 텍스트를 실시간으로 감지하는 예제입니다.

#include <QApplication>
#include <QLineEdit>
#include <rxcpp/rx.hpp>
#include <iostream>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QLineEdit textField;
    textField.show();

    auto textChanges = rxcpp::observable<>::create<QString>(
        [&textField](rxcpp::subscriber<QString> s) {
            QObject::connect(&textField, &QLineEdit::textChanged, [&s](const QString &text) {
                s.on_next(text);
            });
        });

    textChanges.subscribe([](const QString &text) {
        std::cout << "User typed: " << text.toStdString() << std::endl;
    });

    return app.exec();
}

출력 예시 (사용자가 입력한 경우):

User typed: H  
User typed: He  
User typed: Hel  
User typed: Hell  
User typed: Hello  

설명:

  • QLineEdittextChanged() 이벤트를 RxCpp Observable로 변환
  • subscribe()를 통해 사용자가 입력한 텍스트를 실시간으로 감지

4. 버튼 클릭을 일정 횟수 이상 감지하여 처리


RxCpp의 filter() 연산자를 활용하면 버튼이 일정 횟수 이상 클릭되었을 때만 이벤트를 처리할 수 있습니다.

#include <QApplication>
#include <QPushButton>
#include <rxcpp/rx.hpp>
#include <iostream>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QPushButton button("Click Me");
    button.show();

    auto buttonClicks = rxcpp::observable<>::create<int>(
        [&button](rxcpp::subscriber<int> s) {
            QObject::connect(&button, &QPushButton::clicked, [&s]() {
                static int clickCount = 0;
                s.on_next(++clickCount);
            });
        });

    buttonClicks
        .filter([](int count) { return count >= 3; })  // 3회 이상 클릭 시 처리
        .subscribe([](int count) {
            std::cout << "Button clicked " << count << " times. Action triggered!" << std::endl;
        });

    return app.exec();
}

출력 예시:

(Button 클릭 3회 전에는 아무 출력 없음)
Button clicked 3 times. Action triggered!
Button clicked 4 times. Action triggered!
Button clicked 5 times. Action triggered!
...

설명:

  • filter()를 사용하여 3회 이상 클릭된 경우만 출력
  • 특정 이벤트가 지정된 조건을 충족할 때만 반응

5. GUI 이벤트와 비동기 네트워크 요청 결합


GUI 이벤트와 네트워크 요청을 결합하여 버튼 클릭 시 API 요청을 보내고 응답을 처리하는 방식을 RxCpp로 구현할 수도 있습니다.
다음 예제는 버튼 클릭 시 2초 후 응답을 반환하는 비동기 네트워크 요청을 시뮬레이션합니다.

#include <QApplication>
#include <QPushButton>
#include <rxcpp/rx.hpp>
#include <iostream>
#include <chrono>
#include <thread>

auto mockHttpRequest() {
    return rxcpp::observable<>::create<std::string>(
        [](rxcpp::subscriber<std::string> s) {
            std::thread([s]() mutable {
                std::this_thread::sleep_for(std::chrono::seconds(2)); // 네트워크 지연 시간 시뮬레이션
                s.on_next("Response: 200 OK");
                s.on_completed();
            }).detach();
        }
    );
}

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QPushButton button("Send Request");
    button.show();

    auto buttonClicks = rxcpp::observable<>::create<int>(
        [&button](rxcpp::subscriber<int> s) {
            QObject::connect(&button, &QPushButton::clicked, [&s]() {
                s.on_next(1); // 버튼 클릭 감지
            });
        });

    buttonClicks
        .flat_map([](int) { return mockHttpRequest(); })  // 비동기 네트워크 요청
        .subscribe([](std::string response) {
            std::cout << response << std::endl;
        });

    return app.exec();
}

출력 예시 (버튼 클릭 후 2초 후 응답):

Response: 200 OK

설명:

  • flat_map()을 사용하여 버튼 클릭 이벤트를 비동기 네트워크 요청으로 변환
  • subscribe()를 통해 응답을 처리

RxCpp를 활용한 GUI 이벤트 처리 정리


RxCpp를 활용하면 Qt의 Signal-Slot과 결합하여 더욱 직관적인 이벤트 기반 GUI 프로그래밍을 구현할 수 있습니다.

기능RxCpp 연산자예제
버튼 클릭 이벤트 감지create()버튼 클릭 스트림 생성
입력 필드 값 변경 감지create()실시간 입력 감지
특정 횟수 이상 이벤트 감지filter()3회 이상 클릭 시 처리
비동기 네트워크 요청 처리flat_map()API 호출 및 응답 처리

다음 섹션에서는 RxCpp를 활용한 전체 내용 정리를 다루겠습니다.

요약


이번 기사에서는 RxCpp를 활용한 반응형 프로그래밍의 개념과 실전 적용 방법을 다루었습니다.
RxCpp는 이벤트 스트림을 기반으로 한 데이터 처리 및 비동기 프로그래밍을 간결하고 직관적으로 구현할 수 있도록 도와줍니다.

주요 내용 요약

  1. 반응형 프로그래밍의 개념
  • 기존 명령형 프로그래밍과 비교하여 데이터 흐름을 중심으로 이벤트를 처리하는 방식
  • 이벤트 기반 설계가 가능하며, 코드가 간결해지고 유지보수성이 향상됨
  1. RxCpp란?
  • ReactiveX 패턴을 C++에서 사용할 수 있도록 지원하는 라이브러리
  • Observable, Observer, Subscription 등의 개념을 통해 데이터 스트림을 처리
  1. RxCpp 설치 및 환경 설정
  • vcpkg, Conan, 또는 소스 코드 직접 빌드를 통해 RxCpp 설치
  • CMakeLists.txt 설정을 통해 프로젝트에서 활용 가능
  1. RxCpp의 주요 개념과 연산자
  • map(), filter(), merge(), combineLatest() 등을 활용한 데이터 변환 및 조작
  1. RxCpp의 기본적인 코드 예제
  • Observable을 생성하고 subscribe()를 통해 데이터를 처리하는 기본적인 사용법
  1. RxCpp를 활용한 비동기 이벤트 처리
  • interval()을 활용한 일정 시간마다 실행되는 이벤트 스트림
  • create()를 사용하여 백그라운드 스레드에서 비동기적으로 데이터 생성
  1. RxCpp와 멀티스레딩
  • subscribe_on()observe_on()을 활용하여 멀티스레드 환경에서 이벤트 처리
  • 비동기 작업을 수행한 후, 메인 스레드에서 결과를 수신하는 방식
  1. RxCpp를 활용한 GUI 이벤트 처리
  • Qt와 결합하여 버튼 클릭, 텍스트 입력, 네트워크 요청 등을 RxCpp 스트림으로 변환하여 처리

RxCpp 활용의 장점

코드 가독성 향상: 선언형 프로그래밍 스타일을 통해 이벤트 기반 코드를 간결하게 작성 가능
비동기 프로그래밍 간소화: flat_map(), merge() 등을 활용하여 콜백 없이 비동기 데이터 스트림 처리 가능
멀티스레드 이벤트 처리 최적화: subscribe_on(), observe_on()을 사용하여 멀티스레드 환경에서도 안전한 이벤트 흐름 구현
GUI 및 실시간 데이터 처리에 최적화: Qt와 결합하여 GUI 이벤트를 쉽게 처리할 수 있음


RxCpp는 반응형 프로그래밍을 활용하여 C++에서 더욱 효과적으로 이벤트 기반 시스템을 구축하는 강력한 도구입니다.
이번 기사를 통해 RxCpp의 개념과 실용적인 활용법을 익히고, 실제 프로젝트에서 반응형 패턴을 적용하는 데 도움이 되었기를 바랍니다. 🚀

목차
  1. 반응형 프로그래밍이란?
    1. 기존 명령형 프로그래밍과의 차이점
    2. 반응형 프로그래밍의 특징
    3. 반응형 프로그래밍의 활용 사례
  2. RxCpp란 무엇인가?
    1. RxCpp의 주요 특징
    2. RxCpp가 필요한 이유
    3. RxCpp의 기본 개념
    4. RxCpp의 간단한 예제
  3. RxCpp 설치 및 환경 설정
    1. RxCpp 설치 방법
    2. RxCpp를 C++ 프로젝트에서 사용하는 방법
    3. CMake를 이용한 프로젝트 구성
    4. 환경 설정 후 실행 테스트
  4. RxCpp의 주요 개념과 연산자
    1. RxCpp의 주요 개념
    2. RxCpp의 주요 연산자
    3. RxCpp 연산자의 장점
  5. 기본적인 RxCpp 코드 예제
    1. 1. 기본적인 Observable 생성 및 구독
    2. 2. 데이터 변환 (map 연산자 사용)
    3. 3. 특정 조건을 만족하는 데이터만 필터링 (filter 연산자 사용)
    4. 4. 여러 Observable 병합 (merge 연산자 사용)
    5. 5. 비동기 데이터 스트림 생성 (interval 연산자 사용)
    6. RxCpp 예제 정리
  6. RxCpp를 활용한 비동기 이벤트 처리
    1. 1. 비동기 데이터 스트림 생성
    2. 2. 비동기적으로 실행되는 Observable 만들기
    3. 3. subscribe_on()과 observe_on()을 활용한 스레드 전환
    4. 4. 네트워크 요청을 비동기적으로 처리
    5. RxCpp를 활용한 비동기 이벤트 처리 정리
  7. RxCpp와 멀티스레딩
    1. 1. RxCpp에서 멀티스레드를 다루는 방법
    2. 2. 멀티스레드에서 Observable 실행
    3. 3. 백그라운드에서 실행하고 메인 스레드에서 결과 받기
    4. 4. 멀티스레딩을 활용한 이벤트 스트림 처리
    5. RxCpp와 멀티스레딩 정리
  8. 실전 응용: RxCpp를 활용한 GUI 이벤트 처리
    1. 1. RxCpp와 Qt 연동을 위한 준비
    2. 2. Qt 버튼 클릭 이벤트를 RxCpp로 처리
    3. 3. 텍스트 입력 이벤트를 RxCpp로 처리
    4. 4. 버튼 클릭을 일정 횟수 이상 감지하여 처리
    5. 5. GUI 이벤트와 비동기 네트워크 요청 결합
    6. RxCpp를 활용한 GUI 이벤트 처리 정리
  9. 요약
    1. 주요 내용 요약
    2. RxCpp 활용의 장점