# Channels A `Channel` is a lock-free SPSC (single-producer, single-consumer) ring buffer with atomic wait/notify. ## Semantics - **Bounded**: fixed capacity set at construction. Default is 5 items. - **Backpressure**: when full, `push()` throws `ChannelOverflowError` immediately — no blocking, no spin. - **Blocking consumer**: `pop()` blocks until an item is available or the channel is disabled. - **Disable**: `channel.disable()` stops accepting pushes and unblocks any waiting `pop()` with `ChannelClosedError`. ## Storage policy Small trivially-copyable types (≤ 8 bytes) are stored by value. Larger types are heap-allocated and passed via `shared_ptr` — one allocation per push, zero-copy fan-out: ```cpp --8<-- "examples/04_storage_policy/main.cpp:storage_policy_spec" ``` Specialize `kpn::ChannelDataSize` for accurate bandwidth reporting on heap-owning types: ```cpp template<> struct kpn::ChannelDataSize { static std::size_t bytes(const cv::Mat& m) { return m.total() * m.elemSize(); } }; ``` ## Named ports `in<"name">` and `out<"name">` tag nodes for readable wiring: ```cpp --8<-- "examples/02_named_ports/main.cpp:named_port_creation" ``` Named ports are checked at compile time — a typo in a port name is a compile error. ## Capacity tuning Set capacity per node at construction: ```cpp auto node = make_node(/*capacity=*/20); ``` Capacity is rounded up internally to the next power of two. Monitor fill levels via diagnostics to tune for your workload — a too-small capacity causes overflows; a too-large one wastes memory and hides producer/consumer speed mismatches. ## Spin count `Channel` spins for up to ~4 µs (200 `pause` hints at ~20 ns each on x86) before sleeping on a futex. Set to 0 for power-constrained or predominantly-idle pipelines: ```cpp Channel ch(/*capacity=*/5, /*spin_count=*/0); ```