boost::capy::strand

Provides serialized coroutine execution for any executor type.

Synopsis

Declared in <boost/capy/ex/strand.hpp>

template<typename Executor>
class strand;

Description

A strand wraps an inner executor and ensures that coroutines dispatched through it never run concurrently. At most one coroutine executes at a time within a strand, even when the underlying executor runs on multiple threads.

Strands are lightweight handles that can be copied freely. Copies share the same internal serialization state, so coroutines dispatched through any copy are serialized with respect to all other copies.

Invariant

Coroutines resumed through a strand shall not run concurrently.

Implementation

Each strand allocates a private serialization state. Strands constructed from the same execution context share a small pool of mutexes (193 entries) selected by hash; mutex sharing causes only brief contention on the push/pop critical section, never cross‐strand state sharing. Construction cost: one std::make_shared per strand.

Executor Concept

This class satisfies the Executor concept, providing:

  • context() ‐ Returns the underlying execution context

  • on_work_started() / on_work_finished() ‐ Work tracking

  • dispatch(continuation&) ‐ May run immediately if already executing in this strand

  • post(continuation&) ‐ Always queues for later execution

Preconditions

A strand holds only a non‐owning reference to its inner executor's execution context (for example a thread_pool). That context must outlive every post() and dispatch() call; posting or dispatching concurrently with, or after, the context's destruction is undefined behavior. To guarantee this, submit work through run_async or run — whose operations are work‐tracked, so the context's join() waits for them — and call join() on the context before destroying it, rather than posting to a strand from an external thread the context does not track. Destroying the strand handle itself is always safe, including after the context has been destroyed.

Thread Safety

Distinct objects: Safe. Shared objects: Safe.

Example

thread_pool pool(4);
strand strand(pool.get_executor());  // CTAD deduces the executor type

// Continuations are linked intrusively into the strand's queue,
// so each one must outlive its time there. Storage is typically
// owned by the awaitable or operation state that posted it.
continuation c1{h1}, c2{h2}, c3{h3};
strand.post(c1);
strand.post(c2);
strand.post(c3);

Type Aliases

Name

Description

inner_executor_type

The type of the underlying executor.

Member Functions

Name

Description

strand [constructor]

Constructors

operator=

Assignment operators

context

Return the underlying execution context.

dispatch

Dispatch a continuation through the strand.

get_inner_executor

Return the underlying executor.

on_work_finished

Notify that work has finished.

on_work_started

Notify that work has started.

post

Post a continuation to the strand.

running_in_this_thread

Determine whether the strand is running in the current thread.

operator==

Compare two strands for equality.

Deduction Guides

Name

strand<Ex>

Template Parameters

Name

Description

Ex

The type of the underlying executor. Must satisfy the Executor concept.

See Also

Executor

Created with MrDocs