C++ Reactor Pattern: Real-World Engineering Guide

Problem Solved

High-performance, event-driven I/O with few threads, handling many concurrent connections efficiently.

How It Works

  • A single (or small number of) event loop(s) waits for I/O events
  • Handlers respond asynchronously
  • Non-blocking I/O with event notification

STL Usage

#include <functional>
#include <map>
#include <vector>
#include <thread>
#include <atomic>
using namespace std;

class Reactor {
private:
    map<int, function<void()>> handlers_;
    atomic<bool> running_{false};
    thread event_loop_;

    void eventLoop() {
        while (running_) {
            // Wait for events (epoll, select, etc.)
            vector<int> ready_fds = waitForEvents();
            
            for (int fd : ready_fds) {
                if (handlers_.find(fd) != handlers_.end()) {
                    handlers_[fd]();
                }
            }
        }
    }

    vector<int> waitForEvents() {
        // Platform-specific event waiting
        // Returns file descriptors ready for I/O
        // Implementation depends on platform (epoll, kqueue, IOCP)
        return {};
    }

public:
    void registerHandler(int fd, function<void()> handler) {
        handlers_[fd] = handler;
    }

    void start() {
        running_ = true;
        event_loop_ = thread([this]() { eventLoop(); });
    }

    void stop() {
        running_ = false;
        event_loop_.join();
    }
};

class AsyncIOReactor {
private:
    Reactor reactor_;
    // ThreadPool from previous pattern
    // ThreadPool handler_pool_;

public:
    AsyncIOReactor() /* : handler_pool_(4) */ {
        reactor_.start();
    }

    void handleConnection(int socket_fd) {
        reactor_.registerHandler(socket_fd, [this, socket_fd]() {
            // handler_pool_.enqueue([socket_fd]() {
                // Process I/O
                processIO(socket_fd);
            // });
        });
    }

    void processIO(int fd) {
        // Read/write data
    }
};

Example

void reactorExample() {
    AsyncIOReactor reactor;
    
    // Register handlers for different file descriptors
    reactor.handleConnection(1);
    reactor.handleConnection(2);
    
    // Reactor handles events asynchronously
    this_thread::sleep_for(chrono::seconds(1));
}

Use Cases

  • Web servers: Nginx, high-performance HTTP servers
  • Network frameworks: Netty, event-driven networking
  • Database servers: Handle many connections
  • Real-time systems: Low-latency event handling

Key Takeaways

  • Handles many connections with few threads
  • Event-driven, non-blocking I/O
  • High throughput and low latency
  • Common in high-performance servers

Things to Be Careful About

  • Platform-specific: Requires platform I/O APIs (epoll, kqueue, IOCP)
  • Complexity: More complex than thread-per-connection
  • CPU-bound tasks: Should use thread pool for CPU work
  • Error handling: Must handle I/O errors gracefully

Summary

Reactor pattern enables high-performance event-driven I/O, essential for scalable network servers and real-time systems.