docs+test: thread-safety contract for EquipmentDataModel
INTEGRATION.md §3 used to show a sensor-poll thread calling model->svids.set_value() directly while the io_context thread reads the same SVID for an inbound S1F3. That's a data race — there are zero locks anywhere in EquipmentDataModel and there's no intention to add them. The library is single-threaded by design; the doc was just inviting trouble. This commit makes the actual contract explicit: - INTEGRATION.md §3: thread-safety callout box. All access must run on the io_context that drives the HSMS connection. Sensor updates from other threads marshal via asio::post(io.get_executor(), ...). Same applies to set_*_change_handler callbacks (they fire on the io_context thread; observers must be thread-safe or hand work off). - README.md §3 (Monitoring & observability): added a paragraph noting that hooks fire on the io_context thread, blocking I/O inside a handler stalls the dispatcher, and metrics exporters must respect the same contract. - tests/test_thread_safety.cpp: two scenarios that exercise the canonical pattern — N producer threads asio::post sensor updates onto a worker-driven io_context; reads marshal back through the io. Catches obvious regressions (e.g. someone adding a "convenience" cross-thread mutator that bypasses the strand). A passing run isn't proof of race-freedom under ThreadSanitizer — it pins down the *pattern* customers should follow. TSan integration is a separate workstream. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -232,6 +232,16 @@ via a sidecar that polls the data model. Per-CEID emission rates,
|
||||
alarm set/clear rates, T-timer expiry counts, and spool depth
|
||||
form a reasonable starter dashboard.
|
||||
|
||||
**Hooks fire on the io_context thread.** Every `set_*_change_handler`
|
||||
callback the library invokes runs on the connection's io_context
|
||||
(there are no locks anywhere in `EquipmentDataModel`). Metrics
|
||||
exporters and log shippers wired into those callbacks must either be
|
||||
thread-safe themselves or hand the work off (a lock-free queue, a
|
||||
separate exporter thread polling published counters, `asio::post`
|
||||
onto another executor). Doing blocking I/O from inside a handler
|
||||
stalls the dispatcher — keep handlers cheap. See INTEGRATION.md §3
|
||||
for the cross-thread update pattern.
|
||||
|
||||
## 4. High availability
|
||||
|
||||
The library is single-threaded per HSMS connection — that's how
|
||||
|
||||
Reference in New Issue
Block a user