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) ||
| +---------+ +---------+|
| |
+-----------------------------+
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:
- Performance First:
qb
uses a high-performance, lock-free message queue for communication between cores. Its asynchronous I/O engine (qb-io
) is built onlibev
, ensuring minimal overhead for network and timed operations. - 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. - 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. - 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;
}
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)