DEV Community

ISNDEV
ISNDEV

Posted on

Meet `qb`: The High-Performance C++17 Actor Framework You've Been Waiting For

A modern, actor-based C++ framework designed for building scalable, high-performance, and resilient network applications with ease and elegance.

GitHub: https://github.com/isndev/qb


C++ has always been the king of performance, but modern systems demand more: concurrency, scalability, and maintainability. Traditional threading models with mutexes and locks are notoriously difficult to get right. What if you could write highly parallel C++ code that is both safe by design and incredibly fast?

Enter qb, a C++17 framework built on the Actor Model and asynchronous I/O. It's designed from the ground up to leverage multi-core architectures, making complex concurrency patterns feel simple and intuitive.

What is the Actor Model?

The Actor Model is a conceptual model for concurrent computation. It simplifies development by avoiding shared state. Instead of locks and shared memory, your application is built from lightweight, independent "actors."

+-----------------------------+
|         Your System         |
|                             |
|  +---------+     +---------+  <-- Events
|  | Actor A |     | Actor B ||
|  | (State) |<--->| (State) ||
|  +---------+     +---------+|
|      ^               |      |
|      | Events        | Events
|      v               v.     |
|  +---------+     +---------+|
|  | Actor C |     | Actor D ||
|  | (State) |<--->| (State) ||
|  +---------+     +---------+|
|                             |
+-----------------------------+
Enter fullscreen mode Exit fullscreen mode

Each actor has:

  • Private State: No other actor can access its internal state directly.
  • A Mailbox: It receives messages (events) from other actors.
  • Behavior: It processes messages sequentially, one at a time.

This sequential, one-message-at-a-time processing within each actor is the key. It means you never need a mutex to protect an actor's state, eliminating a whole class of concurrency bugs like race conditions and deadlocks.

Why qb? The Core Philosophy

The qb framework is built on a few key principles:

  1. Performance First: qb uses a high-performance, lock-free message queue for communication between cores. Its asynchronous I/O engine (qb-io) is built on libev, ensuring minimal overhead for network and timed operations.
  2. Scalability by Design: By distributing actors across multiple CPU cores, qb applications scale naturally with the available hardware. You can pin actors to specific cores for cache optimization and predictable latency.
  3. Clarity and Simplicity: qb provides high-level abstractions that hide the complexity of threading and synchronization. Writing a concurrent application feels like defining simple objects and the events they react to.
  4. A Rich Ecosystem: qb is more than just a core framework. It comes with powerful modules (qbm) for common backend needs:
    • qbm-http: Build blazing-fast HTTP/1.1 and HTTP/2 servers and clients.
    • qbm-websocket: Add real-time capabilities with a fully compliant WebSocket layer.
    • qbm-pgsql: A high-performance, asynchronous PostgreSQL client.
    • qbm-redis: A feature-rich, asynchronous Redis client.

A Taste of qb: A Simple "Hello World" Actor

Let's see what a basic qb actor looks like. This example features a SimpleActor that receives a message and a SenderActor that sends it, illustrating the core actor-to-actor communication pattern.

From examples/core/example1_simple_actor.cpp

#include <qb/actor.h>
#include <qb/main.h>
#include <iostream>

// 1. Define the message (event)
struct SimpleEvent : public qb::Event {
    int value;
    explicit SimpleEvent(int val) : value(val) {}
};

// 2. Define the receiving actor
class SimpleActor : public qb::Actor {
public:
    bool onInit() override {
        // Register the event handler for SimpleEvent
        registerEvent<SimpleEvent>(*this);
        qb::io::cout() << "SimpleActor: Initialized and ready." << std::endl;
        return true;
    }

    // 3. Define the event handler
    void on(const SimpleEvent& event) {
        qb::io::cout() << "SimpleActor: Received SimpleEvent with value " 
                       << event.value << std::endl;

        // After receiving the 5th event, the actor terminates itself
        if (event.value >= 5) {
            kill();
        }
    }
};

// 4. Define a sending actor
class SenderActor : public qb::Actor, public qb::ICallback {
private:
    qb::ActorId _target_id;
    int _counter = 1;

public:
    explicit SenderActor(qb::ActorId target_id) : _target_id(target_id) {}

    bool onInit() override {
        registerCallback(*this); // Register for periodic calls
        return true;
    }

    void onCallback() override {
        if (_counter > 5) {
            qb::io::cout() << "SenderActor: All events sent. Terminating." << std::endl;
            kill();
            return;
        }

        qb::io::cout() << "SenderActor: Sending event #" << _counter << std::endl;
        // Actors push messages to other actors
        push<SimpleEvent>(_target_id, _counter++);
    }
};


int main() {
    // 5. Set up and run the engine
    qb::Main engine;

    // Create the SimpleActor on core 0
    auto simple_actor_id = engine.addActor<SimpleActor>(0);

    // Create the SenderActor on core 0, giving it the SimpleActor's ID
    engine.addActor<SenderActor>(0, simple_actor_id);

    engine.start();
    engine.join();

    qb::io::cout() << "Application finished." << std::endl;
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Who is qb For?

qb is designed for C++ developers building systems where performance, latency, and scalability are critical.

  • High-Frequency Trading & Finance: Low-latency order matching engines and market data systems.
  • Game Servers: Highly concurrent backends for multiplayer games.
  • IoT & Edge Computing: Efficient data processing and message brokers.
  • High-Performance Web Services: Scalable REST APIs, WebSocket servers, and real-time backends.
  • Distributed Systems: Any application requiring robust, safe communication between components.

If you're looking for a modern C++ framework that embraces concurrency without the headaches of traditional multi-threading, it's time to give qb a try.

Explore the framework on GitHub: https://github.com/isndev/qb

Check out the examples: https://github.com/isndev/qb-examples

Top comments (0)