How to Use `asio bind_cancellation_slot`: Complete Guide with Examples
bind_cancellation_slot is a utility in the Asio library that associates a cancellation slot with any handler, completion token, or function object, enabling automatic cancellation of pending asynchronous operations when a signal is emitted.
The chriskohlhoff/asio repository provides this mechanism through the header asio/bind_cancellation_slot.hpp. By binding a cancellation slot to your asynchronous handlers, you allow the Asio framework to inject cancellation signals directly into your callbacks when operations are aborted.
Core Components
The implementation relies on several cooperating types that work together to wrap handlers and expose cancellation semantics to the Asio execution framework.
cancellation_slot_binder
cancellation_slot_binder is a callable wrapper defined at line 51 in asio/bind_cancellation_slot.hpp. It stores two members: a CancellationSlot and a target object T. When invoked, it forwards all arguments to the wrapped target while making the slot available to Asio's generic algorithms.
This binder is the primary mechanism that connects your handler to the cancellation signal infrastructure.
partial_cancellation_slot_binder
partial_cancellation_slot_binder acts as an intermediate completion token that captures a cancellation slot without immediately binding it to a handler. It enables a "partial application" syntax where you first bind the slot, then supply the handler later.
When invoked, this partial binder produces a full cancellation_slot_binder, allowing you to reuse the same slot binding across multiple operations.
Free Factory Functions
Two overloads of bind_cancellation_slot provide convenient construction:
bind_cancellation_slot(const CancellationSlot&)– Returns apartial_cancellation_slot_binderbind_cancellation_slot(const CancellationSlot&, T&&)– Returns acancellation_slot_binderwrapping the target
These functions handle the template deduction and move semantics automatically.
Trait Specializations
The header provides specializations for async_result (lines 84-136) that enable the binder to function as a completion token. Additionally, associator specializations (lines 79-98) make the binder transparently expose its associated executor, allocator, and cancellation slot to Asio's generic algorithms.
The associated_cancellation_slot trait (lines 100-108) specifically detects when a handler is a cancellation_slot_binder and returns the stored slot, allowing Asio to link the handler to the cancellation signal chain.
Practical Usage Patterns
The test suite in src/tests/unit/bind_cancellation_slot.cpp demonstrates three common patterns for applying cancellation slots to asynchronous operations.
Pattern 1: Binding to Function Objects
The most straightforward approach binds a cancellation slot directly to a function object or std::bind expression:
asio::io_context ioc;
asio::cancellation_signal sig;
int count = 0;
asio::steady_timer t(ioc, asio::chrono::seconds(5));
t.async_wait(
asio::bind_cancellation_slot(sig.slot(),
std::bind(&increment_on_cancel,
&count, std::placeholders::_1)));
In this example, sig.slot() provides the cancellation slot, while std::bind creates a callable matching the timer's handler signature. When sig.emit(asio::cancellation_type::terminal) is called, the timer operation completes immediately with operation_aborted, and your handler receives the error code.
Pattern 2: Binding to Custom Completion Tokens
You can also bind slots to user-defined completion tokens that require async_result specialization:
struct incrementer_token_v1 {
explicit incrementer_token_v1(int* c) : count(c) {}
int* count;
};
struct incrementer_handler_v1 {
explicit incrementer_handler_v1(incrementer_token_v1 t) : count(t.count) {}
void operator()(asio::error_code ec) {
increment_on_cancel(count, ec);
}
int* count;
};
// Async_result specialization for incrementer_token_v1 defined elsewhere...
asio::io_context ioc;
asio::cancellation_signal sig;
int count = 0;
asio::steady_timer t(ioc, asio::chrono::seconds(5));
t.async_wait(
asio::bind_cancellation_slot(sig.slot(),
incrementer_token_v1(&count)));
Here, bind_cancellation_slot wraps the custom token incrementer_token_v1. The associated async_result specialization (see lines 97-105 in the test file) adapts the token so that Asio constructs the handler through the binder, preserving the cancellation slot association.
Pattern 3: Partial Binding (Two-Step Syntax)
For scenarios where you want to bind the slot once and reuse it for multiple operations, use the partial application syntax:
asio::io_context ioc;
asio::cancellation_signal sig;
int count = 0;
auto slot_binder = asio::bind_cancellation_slot(sig.slot());
asio::steady_timer t(ioc, asio::chrono::seconds(5));
t.async_wait(
slot_binder(
std::bind(&increment_on_cancel,
&count, std::placeholders::_1)));
bind_cancellation_slot(sig.slot()) returns a partial_cancellation_slot_binder. The subsequent call operator () supplies the actual handler, producing a full cancellation_slot_binder. This pattern is particularly useful when managing multiple asynchronous operations that share the same cancellation signal.
How Cancellation Propagates
When an asynchronous operation starts, Asio queries the handler's associated cancellation slot via the associated_cancellation_slot trait. If the handler is a cancellation_slot_binder, the trait returns the slot stored inside the binder (as implemented in lines 100-108 of asio/bind_cancellation_slot.hpp).
Consequently, calling sig.emit(...) on the original cancellation_signal causes the bound handler to be invoked with an operation_aborted error code. The binder works for any callable type, including plain function objects, std::bind expressions, or user-defined completion tokens. It also supports nesting: you can bind multiple slots, or bind a slot to a token that itself creates a binder.
Summary
bind_cancellation_slotassociates cancellation slots with handlers inasio/bind_cancellation_slot.hppcancellation_slot_binderwraps your callable and stores the slot at line 51 of the headerpartial_cancellation_slot_binderenables two-step binding syntax for reusable slot configurations- Trait specializations (lines 79-136) make the binder transparent to Asio's executor and cancellation systems
- Three patterns cover direct function binding, custom tokens, and partial application as shown in
src/tests/unit/bind_cancellation_slot.cpp - Cancellation propagation occurs through
associated_cancellation_slotdetection when operations are initiated
Frequently Asked Questions
How do I create a cancellation slot to bind to my handler?
Create a cancellation_signal object, then call its slot() method. This method is defined in asio/cancellation_signal.hpp. The returned slot object can be passed to bind_cancellation_slot to associate it with your handler.
Can I use bind_cancellation_slot with standard function objects like lambdas?
Yes. The cancellation_slot_binder accepts any callable type, including lambdas, std::function objects, and std::bind expressions. The binder forwards all invocations to the wrapped target while maintaining the cancellation slot association.
What happens if I emit a cancellation signal after the operation has already completed?
Cancellation signals only affect pending operations. If the asynchronous operation has already completed and the handler has been invoked, emitting the signal has no effect on that specific operation. The signal affects only operations currently awaiting completion that were started with handlers bound to that signal's slot.
Where can I find the complete implementation of async_result for custom tokens?
The async_result specializations for bind_cancellation_slot are located at lines 84-136 in asio/bind_cancellation_slot.hpp. For examples of custom token implementations, see src/tests/unit/bind_cancellation_slot.cpp, specifically around lines 97-105 where the test suite defines specializations for incrementer_token_v1.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →