256 lines
9.6 KiB
Plaintext
256 lines
9.6 KiB
Plaintext
[/
|
|
/ Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
|
/
|
|
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
/]
|
|
|
|
[section:cancellation Per-Operation Cancellation]
|
|
|
|
[note These type requirements and classes are the low level building blocks of
|
|
cancellation. For most use cases, consider using a higher level abstraction,
|
|
such as [link boost_asio.reference.experimental__make_parallel_group
|
|
experimental::make_parallel_group] or the [link
|
|
boost_asio.overview.composition.cpp20_coroutines.co_ordinating_parallel_coroutines
|
|
logical operators] for `awaitable`.]
|
|
|
|
I/O objects, such as sockets and timers, support object-wide cancellation of
|
|
outstanding asynchronous operations via their `close` or `cancel` member
|
|
functions. However, certain asynchronous operations also support individual,
|
|
targeted cancellation. This per-operation cancellation is enabled by
|
|
specifying that a completion handler has an [link
|
|
boost_asio.reference.associated_cancellation_slot associated cancellation slot]
|
|
which satisfies the [link boost_asio.reference.CancellationSlot CancellationSlot]
|
|
type requirements. A cancellation slot is a lightweight channel used for
|
|
delivering a cancellation request.
|
|
|
|
Given a copy of a user-defined `Handler` object `h`, if an asynchronous
|
|
operation supports cancellation it will obtain a cancellation slot using the
|
|
`get_associated_cancellation_slot` function. For example:
|
|
|
|
boost::asio::associated_cancellation_slot_t<Handler> s
|
|
= boost::asio::get_associated_cancellation_slot(h);
|
|
|
|
The associated cancellation slot must satisfy the CancellationSlot type
|
|
requirements.
|
|
|
|
By default, handlers use a default-constructed [link
|
|
boost_asio.reference.cancellation_slot `cancellation_slot`], which means that
|
|
per-operation cancellation is disabled. The cancellation slot may be customised
|
|
for a particular handler type by specifying a nested type
|
|
`cancellation_slot_type` and member function `get_cancellation_slot()`:
|
|
|
|
class my_handler
|
|
{
|
|
public:
|
|
// Custom implementation of CancellationSlot type requirements.
|
|
typedef my_cancellation_slot cancellation_slot_type;
|
|
|
|
// Return a custom cancellation slot implementation.
|
|
cancellation_slot_type get_cancellation_slot() const noexcept
|
|
{
|
|
return my_cancellation_slot(...);
|
|
}
|
|
|
|
void operator()() { ... }
|
|
};
|
|
|
|
In more complex cases, the `associated_cancellation_slot` template may be
|
|
partially specialised directly:
|
|
|
|
namespace boost { namespace asio {
|
|
|
|
template <typename CancellationSlot>
|
|
struct associated_cancellation_slot<my_handler, CancellationSlot>
|
|
{
|
|
// Custom implementation of CancellationSlot type requirements.
|
|
typedef my_cancellation_slot type;
|
|
|
|
// Return a custom cancellation_slot implementation.
|
|
static type get(const my_handler&,
|
|
const CancellationSlot& a = CancellationSlot()) noexcept
|
|
{
|
|
return my_cancellation_slot(...);
|
|
}
|
|
};
|
|
|
|
} } // namespace boost::asio
|
|
|
|
For convenience, a cancellation slot may be associated with a handler by using
|
|
the [link boost_asio.reference.bind_cancellation_slot `bind_cancellation_slot`]
|
|
function. This is particularly useful when associating a cancellation slot with
|
|
a lambda:
|
|
|
|
boost::asio::async_read(my_socket, my_buffer,
|
|
boost::asio::bind_cancellation_slot(
|
|
my_cancellation_slot,
|
|
[](boost::system::error_code e, std::size_t n)
|
|
{
|
|
...
|
|
}
|
|
)
|
|
);
|
|
|
|
Boost.Asio provides a ready-to-use cancellation slot in the form of [link
|
|
boost_asio.reference.cancellation_slot `cancellation_slot`] and its counterpart [link
|
|
boost_asio.reference.cancellation_signal `cancellation_signal`]. These two classes
|
|
implement a one-to-one pairing of producer (signal) and consumer (slot)
|
|
interfaces. The following example shows its use:
|
|
|
|
class session
|
|
: public std::enable_shared_from_this<proxy>
|
|
{
|
|
...
|
|
|
|
void do_read()
|
|
{
|
|
auto self = shared_from_this();
|
|
socket_.async_read_some(
|
|
buffer(data_),
|
|
boost::asio::bind_cancellation_slot(
|
|
cancel_signal_.slot(),
|
|
[self](boost::system::error_code error, std::size_t n)
|
|
{
|
|
...
|
|
}
|
|
)
|
|
);
|
|
}
|
|
|
|
...
|
|
|
|
void request_cancel()
|
|
{
|
|
cancel_signal_.emit(boost::asio::cancellation_type::total);
|
|
}
|
|
|
|
...
|
|
|
|
boost::asio::cancellation_signal cancel_signal_;
|
|
};
|
|
|
|
A `cancellation_signal` contains a single slot, and consequently a cancellation
|
|
signal/slot pair may be used with at most one operation at a time. However,
|
|
the same slot may be reused for subsequent operations.
|
|
|
|
To support cancellation, an asynchronous operation installs a cancellation
|
|
handler into the slot by calling the slot's `assign` or `emplace` functions.
|
|
This handler will be invoked when a cancellation signal is emitted. A slot
|
|
holds exactly one handler at a time, and installing a new handler will overwrite
|
|
any previously installed handler.
|
|
|
|
When emitting a cancellation signal, the caller must specify a [link
|
|
boost_asio.reference.cancellation_type cancellation type]. This value is a bitmask
|
|
that dictates what guarantees the cancellation target must make if
|
|
successful cancellation occurs. The possible bit values are, from weakest
|
|
to strongest guarantee, are:
|
|
|
|
[table cancellation types
|
|
[
|
|
[Bit]
|
|
[Guarantee if cancellation is successful]
|
|
[Examples where this is the strongest supported guarantee]
|
|
]
|
|
[
|
|
[`terminal`]
|
|
[
|
|
The operation had unspecified side effects, and it is only safe to close
|
|
or destroy the I/O object.
|
|
]
|
|
[
|
|
A stateful implementation of a message framing protocol, where an
|
|
asynchronous operation sends or receives a complete message. If
|
|
cancellation occurs part-way through the message body, it is not possible
|
|
to report a sensible state to the completion handler.
|
|
]
|
|
]
|
|
[
|
|
[`partial`]
|
|
[
|
|
The operation had well-defined side effects, and the completion
|
|
handler for the operation indicates what these side effects were.
|
|
]
|
|
[
|
|
Composed operations such as `async_read` and `async_write`. If cancellation
|
|
occurs before all bytes are transferred, the completion handler is passed
|
|
the total bytes transferred so far. The caller may use this information
|
|
to start another operation to transfer the remaining bytes.
|
|
]
|
|
]
|
|
[
|
|
[`total`]
|
|
[
|
|
The operation had no side effects that are observable through the API.
|
|
]
|
|
[
|
|
Low level system calls that transfer either zero or non-zero bytes.[br]
|
|
[br]
|
|
Wait-for-readiness operations that have no side effects, even when
|
|
successful.[br]
|
|
[br]
|
|
A fully buffered message framing protocol implementation, where partial
|
|
messages are stored so that they may be reused on the next operation.
|
|
]
|
|
]
|
|
]
|
|
|
|
For example, if application logic requires that an operation complete with
|
|
all-or-nothing side effects, it should emit only the `total` cancellation type.
|
|
If this type is unsupported by the target operation, no cancellation will
|
|
occur.
|
|
|
|
Furthermore, a stronger guarantee always satisfies the requirements of a weaker
|
|
guarantee. The `partial` guarantee still satisfies the `terminal` guarantee.
|
|
The `total` guarantee satisfies both `partial` and `total`. This means that
|
|
when an operation supports a given cancellation type as its strongest
|
|
guarantee, it should honour cancellation requests for any of the weaker
|
|
guarantees.
|
|
|
|
Cancellation requests should not be emitted during an asynchronous operation's
|
|
initiating function. Cancellation requests that are emitted before an operation
|
|
starts have no effect. Similarly, cancellation requests made after completion
|
|
have no effect.
|
|
|
|
When emitting a cancellation signal, the thread safety rules apply as if
|
|
calling a member function on the target operation's I/O object. For
|
|
non-composed operations, this means that it is safe to emit the cancellation
|
|
signal from any thread provided there are no other concurrent calls to the I/O
|
|
object, and no other concurrent cancellation signal requests. For composed
|
|
operations, care must be taken to ensure the cancellation request does not
|
|
occur concurrently with the operation's intermediate completion handlers.
|
|
|
|
[heading Supported Operations]
|
|
|
|
Consult the documentation for individual asynchronous operations for their
|
|
supported cancellation types, if any. The ability to cancel individual
|
|
operations, or composed operations, is currently supported by:
|
|
|
|
* timers
|
|
* sockets on POSIX and Windows
|
|
* POSIX descriptors
|
|
* Windows HANDLEs
|
|
* signal sets
|
|
* serial ports
|
|
* SSL streams
|
|
* all Boost.Asio-provided composed operations such as `async_read` and `async_write`
|
|
* compositions based on `async_compose`
|
|
* C++20 coroutines that use `awaitable`
|
|
* C++20 coroutines that use `experimental::coro`
|
|
* the `experimental::parallel_group` operation
|
|
* the `experimental::promise` class
|
|
|
|
[heading See Also]
|
|
|
|
[link boost_asio.reference.CancellationSlot CancellationSlot],
|
|
[link boost_asio.reference.associated_cancellation_slot associated_cancellation_slot],
|
|
[link boost_asio.reference.bind_cancellation_slot bind_cancellation_slot],
|
|
[link boost_asio.reference.cancellation_signal cancellation_signal],
|
|
[link boost_asio.reference.cancellation_slot cancellation_slot],
|
|
[link boost_asio.reference.cancellation_state cancellation_state],
|
|
[link boost_asio.reference.cancellation_type cancellation_type],
|
|
[link boost_asio.reference.get_associated_cancellation_slot get_associated_cancellation_slot],
|
|
[link boost_asio.reference.experimental__parallel_group experimental::parallel_group],
|
|
[link boost_asio.reference.experimental__make_parallel_group experimental::make_parallel_group]
|
|
|
|
[endsect]
|