|
DelegateMQ
|
DelegateMQ is a C++ header-only library for invoking any callable (e.g., function, method, lambda):
It serves as a messaging layer for C++ applications, providing thread-safe asynchronous callbacks, a Signal & Slot mechanism, and inter-thread data transfer. The library is unit-tested and is designed for easy portability to any platform (Windows, Linux, RTOS, bare-metal).
Key Use Cases
MakeDelegate – Creates a delegate instance bound to a callable (lambda, function, or method).MulticastDelegateSafe – A thread-safe container of delegates, allowing broadcast-style invocation.SignalSafe - A thread-safe Signal implementation that returns a connection handle upon subscription (Signal/Slot pattern).Thread – A cross-platform thread class capable of asynchronous delegate invocation.Invoke MsgOut() using delegates.
Subscriber connects to Publisher signal to receive asynchronous callbacks. Connection is automatically managed via RAII.
Multiple callables targets stored and broadcast 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, signal-slots, 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 simplify multithreaded programming by allowing you to invoke functions across thread boundaries safely and effortlessly. This enables the Active Object pattern, where method execution is decoupled from method invocation. The library automatically marshals all arguments—whether passed by value, pointer, or reference—ensuring thread safety without manual locking or complex queue management.
Key Features:
std::future to retrieve results later.Supported Platforms:
Remote delegates extend the library to enable Remote Procedure Calls (RPC) across process or network boundaries. This allows you to invoke a function on a remote machine as easily as calling a local function. The system automatically handles argument marshaling, serialization, and thread dispatching.
Key Features:
Supported Integrations:
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.See Delegate Invocation Semantics for information on target callable invocation and argument handling based on the delegate type.
DelegateMQ 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 Example Projects to build remote delegate project examples. See Porting Guide for details on porting to a new platform.
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 |
| Object Lifetime | Thread-safe management via smart pointers (std::weak_ptr) prevents async invocation on destroyed objects (no dangling pointers). |
| 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). |
| Watchdog | Configurable timeout to detect and handle unresponsive threads. |
| Signal and Slots | Standard Signal-Slot pattern implementation (Signal / SignalSafe). Supports Connect(), connection handles, and RAII-based automatic disconnection (ScopedConnection). |
| 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. "super loop"). |
| 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.