- 
          
 - 
                Notifications
    
You must be signed in to change notification settings  - Fork 12
 
async_system.md
The qb::io::async namespace is the powerhouse behind qb-io's non-blocking capabilities. It provides a complete, event-driven asynchronous programming model built around a high-performance event loop. While it seamlessly integrates with the qb-core actor system, qb::io::async is also designed to be fully usable as a standalone toolkit for any C++17 application requiring efficient asynchronous operations.
At the heart of the asynchronous system is the qb::io::async::listener class (defined in qb/io/async/listener.h). This class is your primary interface to the event loop.
- 
Underlying Engine: 
listenerwraps thelibevC library, known for its high performance and portability across POSIX systems (epoll, kqueue) and Windows (IOCP, select). - 
Thread-Local Instance (
listener::current): Crucially,qb-ioprovides a thread-local static instance of thelistenernamedqb::io::async::listener::current. This means each thread that intends to perform asynchronous operations withqb-iohas its own dedicated event loop manager. You don't need to pass listener objects around; you simply accesslistener::currentfrom the thread where you want to register or manage events. - 
Initialization (Standalone Usage): If you're using 
qb-iowithoutqb-core, you must initialize the listener for each participating thread by callingqb::io::async::init();once per thread before using otherqb::io::asyncfeatures. (When usingqb-core,qb::Mainhandles this for itsVirtualCorethreads). 
- 
Monitoring Event Sources: The 
listenercontinuously monitors various sources of events:- 
I/O Events (
qb::io::async::event::io): Readiness of file descriptors (sockets, pipes, files) for reading or writing. - 
Timer Events (
qb::io::async::event::timer): Expiration of scheduled timers for delayed or periodic actions. - 
Signal Events (
qb::io::async::event::signal): Asynchronous notification of operating system signals (e.g., SIGINT, SIGTERM). - 
File System Stat Events (
qb::io::async::event::file): Notifications about changes to file attributes (used byfile_watcheranddirectory_watcher). 
 - 
I/O Events (
 - 
Event Dispatching: When an event source becomes active (e.g., data arrives on a socket, a timer expires), the 
listeneridentifies the corresponding registered handler (an object implementingIRegisteredKernelEvent) and invokes itsinvoke()method. This, in turn, typically calls the user-definedon(SpecificEvent&)method within the I/O component or handler class. 
For the listener to process events, its loop must be actively run:
- 
qb::io::async::run(int flag = 0): This function executes the event loop forlistener::current. Theflagargument controls its behavior:- 
0(default): Runs the loop untilqb::io::async::break_parent()is called or no active event watchers remain. This is a blocking call. - 
EVRUN_ONCE: Waits for at least one event to occur, processes the block of available events, and then returns. - 
EVRUN_NOWAIT: Checks for any immediately pending events, processes them, and returns without waiting if none are pending. 
 - 
 - 
qb::io::async::run_once(): Convenience forrun(EVRUN_ONCE). - 
qb::io::async::run_until(const bool& status_flag): Runs the loop withEVRUN_NOWAITrepeatedly as long asstatus_flagis true. - 
qb::io::async::break_parent(): Signalslistener::currentto stop its currentrun()cycle. 
// Standalone qb-io example sketch
#include <qb/io/async.h>
#include <iostream>
#include <atomic>
std::atomic<bool> g_is_running = true;
void my_periodic_task() {
    std::cout << "Periodic task executed at: " << qb::UtcTimePoint::now().to_iso8601() << std::endl;
    if (g_is_running) {
        // Reschedule self
        qb::io::async::callback(my_periodic_task, 1.0); // Every 1 second
    }
}
int main() {
    qb::io::async::init(); // Initialize listener for the main thread
    std::cout << "Starting standalone qb-io event loop demo.\n";
    std::cout << "Press Ctrl+C to exit (if signal handling is set up, or wait for tasks).\n";
    // Schedule an initial periodic task
    qb::io::async::callback(my_periodic_task, 1.0);
    // Schedule a one-shot task to stop the loop after 5 seconds
    qb::io::async::callback([]() {
        std::cout << "5 seconds elapsed. Signaling application to stop.\n";
        g_is_running = false;
        qb::io::async::break_parent(); // Request the run loop to exit
    }, 5.0);
    // Run the event loop until break_parent() is called or g_is_running is false
    // In a real app, this might be: while(g_is_running) { qb::io::async::run(EVRUN_ONCE); /* other logic */ }
    qb::io::async::run(); // Runs until break_parent() or no more active watchers
    std::cout << "Event loop finished.\n";
    return 0;
}The listener::current.registerEvent<_Event, _Actor, _Args...>(actor, args...) method is the core mechanism for associating an event watcher (like qb::io::async::event::io or timer) with a handler object (_Actor) and the event loop.
- 
_Event: The qb-io event type (e.g.,qb::io::async::event::timer). This wraps a specificlibevwatcher. - 
_Actor: The class instance that will handle the event (must have anon(_Event&)method). - 
_Args...: Arguments specific to thelibevwatcher being set up (e.g., file descriptor andEV_READ/EV_WRITEflags for anevent::iowatcher, or timeout values for anevent::timer). 
Most qb-io components designed for asynchronous operations (e.g., those inheriting from qb::io::async::io, qb::io::async::file_watcher, or qb::io::async::with_timeout) handle this registration internally when they are constructed or started.
(qb/io/async/io.h)
This utility function provides a straightforward way to schedule a callable (lambda, function pointer, functor) for execution by the current thread's event loop, optionally after a delay.
- Execution: The callback runs on the same thread that scheduled it.
 - 
Lifetime: The internal timer object (
qb::io::async::Timeout) created bycallbackis self-managing; it registers with the listener and deletes itself after the callback is invoked. - 
Usage: 
qb::io::async::callback(my_function, delay_seconds);orqb::io::async::callback([]{ /* lambda body */ }); - Use Cases: Delaying operations, breaking work into smaller non-blocking chunks, scheduling retries, and simple periodic tasks (by re-scheduling from within the callback).
 
(See practical examples in: Core Concepts: Asynchronous I/O Model in QB for actor-centric usage, and example1_async_io.cpp for general usage.)
(qb/io/async/io.h)
This CRTP base class allows you to easily add timeout functionality to your own classes.
- 
Inheritance: 
class MyClass : public qb::io::async::with_timeout<MyClass> { ... }; - 
Handler Method: Implement 
void on(qb::io::async::event::timer const& event)inMyClassto define what happens when the timeout occurs. - 
Control:
- The constructor 
with_timeout(timeout_in_seconds)initializes and starts the timer. - Call 
updateTimeout()on any activity that should reset the timeout countdown. - Use 
setTimeout(new_duration_seconds)to change the timeout period or disable it (by passing0.0). 
 - The constructor 
 
This mechanism is ideal for implementing inactivity timeouts in network sessions, operation timeouts, or any scenario where an action needs to be taken if something doesn't happen within a specific timeframe.
(A detailed example is available in: Core Concepts: Asynchronous I/O Model in QB and test-async-io.cpp::TimerHandler)
(qb/io/async/event/all.h)
qb-io defines a suite of event structures used to notify components about various asynchronous occurrences. When building custom I/O components (often by inheriting from qb::io::async::input, qb::io::async::output, or qb::io::async::io), you will typically override on(SpecificEvent&) methods to handle these:
- 
disconnected: A network connection was closed or an error occurred. - 
eof: End-of-file reached on an input stream; no more data to read. - 
eos: End-of-stream reached on an output stream; all buffered data has been sent. - 
file: Attributes of a monitored file or directory have changed (used byfile_watcher). - 
io: Raw low-level I/O readiness on a file descriptor (e.g., socket is readable/writable). - 
pending_read/pending_write: Data remains in input/output buffers after a partial operation. - 
signal: An OS signal was caught. - 
timer/timeout: A previously set timer or timeout has expired. 
These events form the backbone of communication between the listener and the I/O handling components, enabling a fully event-driven architecture.
(Next: QB-IO: Transports to see how these async mechanisms are applied to TCP, UDP, etc.**)