84 lines
3.1 KiB
C++
84 lines
3.1 KiB
C++
// Example 16 — Event Callbacks: overflow and node-stopped signals
|
|
//
|
|
// Two complementary observation mechanisms:
|
|
//
|
|
// 1. Per-node overflow callback set_overflow_callback()
|
|
// Fired (with a timestamp) when a node's output channel is full and an
|
|
// item is dropped. Useful for targeted monitoring of a specific node.
|
|
//
|
|
// 2. Network-level event handler net.set_event_handler()
|
|
// Aggregate callback covering every node: receives the node name, a
|
|
// NodeEvent (Overflow or Closed), and a timestamp. Register once and
|
|
// observe the whole network.
|
|
//
|
|
// Pipeline: [fast_source] --int--> [slow_sink]
|
|
//
|
|
// fast_source produces at ~500 items/s; slow_sink consumes at ~20 items/s.
|
|
// The channel capacity is 3, so overflows appear within milliseconds.
|
|
|
|
#include <kpn/kpn.hpp>
|
|
#include <atomic>
|
|
#include <chrono>
|
|
#include <iostream>
|
|
#include <thread>
|
|
|
|
using namespace kpn;
|
|
using namespace std::chrono;
|
|
|
|
// ── Node functions ────────────────────────────────────────────────────────────
|
|
|
|
// --8<-- [start:node_fns]
|
|
static std::atomic<int> g_seq{0};
|
|
|
|
static int fast_source() {
|
|
std::this_thread::sleep_for(milliseconds(2)); // ~500/s
|
|
return g_seq.fetch_add(1);
|
|
}
|
|
|
|
static void slow_sink(int x) {
|
|
std::this_thread::sleep_for(milliseconds(50)); // ~20/s
|
|
std::cout << " consumed: " << x << '\n';
|
|
}
|
|
// --8<-- [end:node_fns]
|
|
|
|
// ── main ──────────────────────────────────────────────────────────────────────
|
|
|
|
int main() {
|
|
auto src = make_node<fast_source>(/*capacity=*/3);
|
|
auto snk = make_node<slow_sink> (/*capacity=*/3);
|
|
|
|
// --8<-- [start:per_node_callback]
|
|
// Per-node overflow callback — no node name needed, known at registration.
|
|
std::atomic<int> overflow_count{0};
|
|
src.set_overflow_callback([&](steady_clock::time_point ts) {
|
|
auto ms = duration_cast<milliseconds>(ts.time_since_epoch()).count();
|
|
std::cerr << "[overflow] fast_source at t=" << ms << "ms\n";
|
|
overflow_count.fetch_add(1);
|
|
});
|
|
// --8<-- [end:per_node_callback]
|
|
|
|
Network net;
|
|
|
|
// --8<-- [start:network_event_handler]
|
|
// Network-level aggregate handler — covers every node, includes node name.
|
|
net.set_event_handler([](std::string_view name, NodeEvent ev,
|
|
steady_clock::time_point ts) {
|
|
auto ms = duration_cast<milliseconds>(ts.time_since_epoch()).count();
|
|
std::string_view kind = (ev == NodeEvent::Overflow) ? "overflow" : "closed";
|
|
std::cerr << "[net:" << kind << "] node=" << name << " t=" << ms << "ms\n";
|
|
});
|
|
// --8<-- [end:network_event_handler]
|
|
|
|
net.add("source", src)
|
|
.add("sink", snk)
|
|
.connect("source", src.output<0>(), "sink", snk.input<0>())
|
|
.build()
|
|
.start();
|
|
|
|
std::this_thread::sleep_for(milliseconds(300));
|
|
net.stop();
|
|
|
|
std::cout << "\nTotal overflows observed by per-node callback: "
|
|
<< overflow_count.load() << '\n';
|
|
}
|