DelegateMQ
|
DelegateMQ is a C++ header-only library for invoking any callable (e.g., function, method, lambda):
It unifies function calls across threads or systems via a simple delegate interface. DelegateMQ is thread-safe, unit-tested, and easy to port to any platform.
MakeDelegate
– Creates a delegate instance bound to a callable (lambda, function, or method).MulticastDelegateSafe
– A thread-safe container of delegates, allowing broadcast-style invocation.Thread
– A cross-platform thread class capable of asynchronous delegate invocation.Subscriber
registers with Publisher
to receive asynchronous callbacks.
Multiple callables targets stored and invoked asynchronously.
Asynchronous public API reinvokes StoreAsync()
call onto the internal m_thread
context.
In C++, a delegate function object encapsulates a callable entity, such as a function, method, or lambda, so it can be invoked later. A delegate is a type-safe wrapper around a callable function that allows it to be passed around, stored, or invoked at a later time, typically within different contexts or on different threads. Delegates are particularly useful for event-driven programming, callbacks, asynchronous APIs, or when you need to pass functions as arguments.
Originally published on CodeProject at Asynchronous Multicast Delegates in Modern C++ with a perfect 5.0 article feedback rating.
Synchronous delegates invoke the target function anonymously within the current execution context. No external library dependencies are required.
Asynchronous delegates support both non-blocking and blocking invocation modes, including optional timeouts. The library enables anonymous invocation of any callable target, regardless of the number or type of arguments, or the presence of a return value. All argument types are supported — including by value, pointers, pointer-to-pointer, and references.
The delegate library abstracts the complexities of invoking functions across thread boundaries. Concrete examples are provided below, with straightforward paths to porting across platforms.
Remote delegates enable function invocation across processes or processors using customizable serialization and transport mechanisms. All argument data is marshaled to support remote callables with any function signature. The design allows easy integration with new transport or serialization libraries. Concrete examples using supported libraries are provided below.
It is always safe to call the delegate. In its null state, a call will not perform any action and will return a default-constructed return value. A delegate behaves like a normal pointer type: it can be copied, compared for equality, called, and compared to nullptr
. Const correctness is maintained; stored const objects can only be called by const member functions.
A delegate instance can be:
nullptr
.Typical use cases are:
std::async
Thread TargetingDelegateMQ uses an external thread, transport, and serializer, all of which are based on simple, well-defined interfaces.
DelegateMQ Layer Diagram
The library's flexible CMake build options allow for the inclusion of only the necessary features. Synchronous, asynchronous, and remote delegates can be used individually or in combination.
To build and run DelegateMQ, follow these simple steps. The library uses CMake to generate build files and supports Visual Studio, GCC, and Clang toolchains.
cmake -B build .
build
directory.See Sample Projects to build other project examples.
Systems are composed of various design patterns or libraries to implement callbacks, asynchronous APIs, and inter-thread or inter-processor communications. These elements typically lack shared commonality. Callbacks are one-off implementations by individual developers, messages between threads rely on OS message queues, and communication libraries handle data transfer complexities. However, the underlying commonality lies in the need to move argument data to the target handler function, regardless of its location.
The DelegateMQ middleware effectively encapsulates all data movement and function invocation within a single library. Whether the target function is a static method, class method, or lambda—residing locally in a separate thread or remotely on a different processor—the library ensures the movement of argument data (marshalling when necessary) and invokes the target function. The low-level details of data movement and function invocation are neatly abstracted from the application layer.
DelegateMQ at a glance.
Category | DelegateMQ |
---|---|
Purpose | Unify callable invocation across threads, processes, and networks |
Usages | Callbacks (synchronous and asynchronous), asynchronous API's, communication and data distribution, and more |
Library | Allows customizing data sharing between threads, processes, or processors |
Complexity | Lightweight and extensible through external library interfaces and full source code |
Threads | No internal threads. External configurable thread interface portable to any OS (IThread ). |
Multicast | Broadcast invoke anonymous callable targets onto multiple threads |
Message Priority | Asynchronous delegates support prioritization to ensure timely execution of critical messages |
Serialization | External configurable serialization data formats, such as MessagePack, RapidJSON, or custom encoding (ISerializer ) |
Transport | External configurable transport, such as ZeroMQ, TCP, UDP, serial, data pipe or any custom transport (ITransport ) |
Timeouts and Retries | Provided by a communication library (e.g. ZeroMQ REQ-REP (Request-Reply)), TCP/IP stack, or custom solution (ITransportMonitor ) |
Message Buffering | Remote delegate message buffering provided by a communication library (e.g. ZeroMQ) or custom solution within transport |
Dynamic Memory | Heap or DelegateMQ fixed-block allocator |
Debug Logging | Debug logging using spdlog C++ logging library |
Error Handling | Configurable for return error code, assert or exception |
Embedded Friendly | Yes. Any OS such as Windows, Linux and FreeRTOS. An OS is not required (i.e. "superloop"). |
Operation System | Any. Custom IThread implementation may be required. |
Language | C++17 or higher |
Alternative asynchronous implementations similar in concept to DelegateMQ, simpler, and less features.
Repositories utilizing the DelegateMQ library.