From 9f855b69b271af44312dcaebbbf0f5c55e4135e0 Mon Sep 17 00:00:00 2001 From: David Bakin Date: Fri, 19 Jun 2026 11:58:35 -0700 Subject: [PATCH 1/9] Update CMakeLists for newer subdirectory names Signed-off-by: David Bakin --- CMakeLists.txt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 58fa73f..85aab94 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,11 +35,12 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON) # Add Chapters # ------------------------------------------------------------ +add_subdirectory(SetupChapter) add_subdirectory(Common) -add_subdirectory(Chapter4-TypeErasure) -add_subdirectory(Chapter8-SensorPipelines) -add_subdirectory(Chapter9-SystemController) -add_subdirectory(Chapter10-Reactor) -add_subdirectory(Chapter11-FusionTiming) -add_subdirectory(Chapter12-DeterministicFusionAndOutput) +add_subdirectory(Chapter3-TypeErasure) +add_subdirectory(Chapter7-SensorPipelines) +add_subdirectory(Chapter8-SytemCompositionAndControl) # note spelling error +add_subdirectory(Chapter9-IntegratingExternalInputs) +add_subdirectory(Chapter10-FusionTiming) +add_subdirectory(Chapter11-DeterministicFusionAndOutput) add_subdirectory(ExternalDataSource) From fc2d3b00a1752d075319299d742d76639f1afd21 Mon Sep 17 00:00:00 2001 From: David Bakin Date: Mon, 22 Jun 2026 20:13:18 -0700 Subject: [PATCH 2/9] Updated Chap 7 demo - include counts related to r/w queue behavior Signed-off-by: David Bakin --- .../include/GpsMeasurement.h | 0 .../include/SensorPipeline.h | 8 ++++ .../src/SensorPipeline.cpp | 38 +++++++++++++++---- Chapter7-SensorPipelines/src/main.cpp | 5 ++- Common/CMakeLists.txt | 1 + Common/include/Counters.h | 25 ++++++++++++ global | 0 7 files changed, 69 insertions(+), 8 deletions(-) delete mode 100644 Chapter7-SensorPipelines/include/GpsMeasurement.h create mode 100644 Common/include/Counters.h delete mode 100644 global diff --git a/Chapter7-SensorPipelines/include/GpsMeasurement.h b/Chapter7-SensorPipelines/include/GpsMeasurement.h deleted file mode 100644 index e69de29..0000000 diff --git a/Chapter7-SensorPipelines/include/SensorPipeline.h b/Chapter7-SensorPipelines/include/SensorPipeline.h index 5fd18b1..162bf51 100644 --- a/Chapter7-SensorPipelines/include/SensorPipeline.h +++ b/Chapter7-SensorPipelines/include/SensorPipeline.h @@ -5,6 +5,7 @@ #include #include "readerwriterqueue.h" +#include "Counters.h" #include "AnyMeasurement.h" @@ -25,6 +26,8 @@ class SensorPipeline void stop(); void join(); + void status(std::ostream& os); + private: void producerLoop(); void consumerLoop(); @@ -34,4 +37,9 @@ class SensorPipeline std::thread m_producerThread; std::thread m_consumerThread; std::atomic m_running { false }; + + Counter producer_enqueued; + Counter producer_blocked; + Counter consumer_blocked; + Counter consumer_dequeued; }; diff --git a/Chapter7-SensorPipelines/src/SensorPipeline.cpp b/Chapter7-SensorPipelines/src/SensorPipeline.cpp index eb1f467..1fb6b20 100644 --- a/Chapter7-SensorPipelines/src/SensorPipeline.cpp +++ b/Chapter7-SensorPipelines/src/SensorPipeline.cpp @@ -64,6 +64,14 @@ void SensorPipeline::join() } } +void SensorPipeline::status(std::ostream& os) +{ + os << "Producer enqueued: " << producer_enqueued << "\n" + << " blocked: " << producer_blocked << "\n" + << "Consumer blocked: " << consumer_blocked << "\n" + << " dequeued: " << consumer_dequeued << "\n"; +} + void SensorPipeline::producerLoop() { PositionProducer producer; @@ -81,12 +89,19 @@ void SensorPipeline::producerLoop() weather::AnyMeasurement msg(header, pos); - while (m_running.load() && !m_queue.try_enqueue(msg)) + while (m_running.load()) { - std::this_thread::sleep_for(std::chrono::microseconds(50)); + if (m_queue.try_enqueue(msg)) + { + producer_enqueued++; + break; + } else { + producer_blocked++; + std::this_thread::sleep_for(std::chrono::microseconds(50)); +; } } - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); } } @@ -107,9 +122,11 @@ void SensorPipeline::consumerLoop() { if (!m_queue.try_dequeue(msg)) { + consumer_blocked++; std::this_thread::sleep_for(std::chrono::microseconds(50)); continue; } + consumer_dequeued++; const weather::Position* pos = msg.try_get(); if (pos != nullptr) @@ -123,12 +140,19 @@ void SensorPipeline::consumerLoop() } // Optional drain after stop (keeps output tidy) - while (m_queue.try_dequeue(msg)) + std::cerr << "--Draining queue--\n"; + while (true) { - const weather::Position* pos = msg.try_get(); - if (pos != nullptr) + if (m_queue.try_dequeue(msg)) { - consumer.consume(*pos); + consumer_dequeued++; + const weather::Position* pos = msg.try_get(); + if (pos != nullptr) + { + consumer.consume(*pos); + } + } else { + break; } } } diff --git a/Chapter7-SensorPipelines/src/main.cpp b/Chapter7-SensorPipelines/src/main.cpp index 6f8efb8..906f108 100644 --- a/Chapter7-SensorPipelines/src/main.cpp +++ b/Chapter7-SensorPipelines/src/main.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include "SensorPipeline.h" @@ -17,6 +19,7 @@ int main() pipeline.stop(); pipeline.join(); + pipeline.status(std::cerr); + return 0; } - diff --git a/Common/CMakeLists.txt b/Common/CMakeLists.txt index fae86d6..0c4022b 100644 --- a/Common/CMakeLists.txt +++ b/Common/CMakeLists.txt @@ -10,6 +10,7 @@ add_library(Common STATIC # Public headers (explicit) include/ImmutableByteView.h include/MutableByteView.h + include/Counters.h include/Status.h diff --git a/Common/include/Counters.h b/Common/include/Counters.h new file mode 100644 index 0000000..c272227 --- /dev/null +++ b/Common/include/Counters.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + + +// A counter that is isolated on a cache line. It isn't thread-safe - it must be accessed only +// on one thread at a time - but on that thread it won't cause a cache line to be sloshed around +// from processor to processor. +struct Counter +{ + void incr() { ++value; } + void operator++() { incr(); } + void operator++(int) { incr(); } + + operator unsigned long() const { return value.load(); } + +private: +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Winterference-size" + static constexpr auto cache_line_size = std::hardware_destructive_interference_size; +#pragma GCC diagnostic pop + alignas(cache_line_size) std::atomic value {0}; + char _padding_[cache_line_size - sizeof(long)]; +}; diff --git a/global b/global deleted file mode 100644 index e69de29..0000000 From 2551a928db03ba761e572e6dbb10be537e394713 Mon Sep 17 00:00:00 2001 From: David Bakin Date: Tue, 23 Jun 2026 16:10:14 -0700 Subject: [PATCH 3/9] fix warning about possible loss of precision in jitter_test Signed-off-by: David Bakin --- Common/include/Counters.h | 5 ++--- SetupChapter/jitter_test.cpp | 6 ++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Common/include/Counters.h b/Common/include/Counters.h index c272227..bca08e5 100644 --- a/Common/include/Counters.h +++ b/Common/include/Counters.h @@ -4,9 +4,8 @@ #include -// A counter that is isolated on a cache line. It isn't thread-safe - it must be accessed only -// on one thread at a time - but on that thread it won't cause a cache line to be sloshed around -// from processor to processor. +// A counter that is isolated on a cache line. Thread-safe plus isolated on a single cache line +// so incrementing it won't have interference penalties. struct Counter { void incr() { ++value; } diff --git a/SetupChapter/jitter_test.cpp b/SetupChapter/jitter_test.cpp index f8a3587..da980d2 100644 --- a/SetupChapter/jitter_test.cpp +++ b/SetupChapter/jitter_test.cpp @@ -80,9 +80,8 @@ int main(int argc, char* argv[]) const long double avg_abs = sum_abs / static_cast(abs_jitter.size()); std::sort(abs_jitter.begin(), abs_jitter.end()); - const std::size_t idx_99 = static_cast( - (abs_jitter.size() - 1) * 0.99 - ); + const std::size_t idx_99 = static_cast(static_cast(abs_jitter.size() - 1) * 0.99); + const long long p99_abs = abs_jitter[idx_99]; std::cout << "Jitter statistics (nanoseconds)\n"; @@ -94,4 +93,3 @@ int main(int argc, char* argv[]) return 0; } - From 59e581f461c17738a055a883c42c7714718da212 Mon Sep 17 00:00:00 2001 From: David Bakin Date: Wed, 24 Jun 2026 15:43:26 -0700 Subject: [PATCH 4/9] Comments for the sensor pipeline lifecycle Signed-off-by: David Bakin --- Chapter7-SensorPipelines/include/SensorPipeline.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Chapter7-SensorPipelines/include/SensorPipeline.h b/Chapter7-SensorPipelines/include/SensorPipeline.h index 162bf51..ed46af3 100644 --- a/Chapter7-SensorPipelines/include/SensorPipeline.h +++ b/Chapter7-SensorPipelines/include/SensorPipeline.h @@ -16,15 +16,16 @@ class SensorPipeline { public: - explicit SensorPipeline(std::size_t capacity); + explicit SensorPipeline(std::size_t capacity); // creates this "holder" but doesn't start work ~SensorPipeline(); SensorPipeline(const SensorPipeline&) = delete; SensorPipeline& operator=(const SensorPipeline&) = delete; - void start(); - void stop(); - void join(); + void start(); // create pipeline (including its threads) and start flow + void stop(); // _request_ work to end (does not block) + void join(); // wait for completion of pipeline (blocks) and end threads (and resources) + // ...now SensorPipeline is safe to destruct void status(std::ostream& os); From 3ccd34eae4f772fd2fce792454d2119ebf01f103 Mon Sep 17 00:00:00 2001 From: David Bakin Date: Wed, 24 Jun 2026 15:44:07 -0700 Subject: [PATCH 5/9] test scaffold that allows bursting producer measurements, leading to queue-full situations Signed-off-by: David Bakin --- .../src/SensorPipeline.cpp | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/Chapter7-SensorPipelines/src/SensorPipeline.cpp b/Chapter7-SensorPipelines/src/SensorPipeline.cpp index 1fb6b20..d7f3cd2 100644 --- a/Chapter7-SensorPipelines/src/SensorPipeline.cpp +++ b/Chapter7-SensorPipelines/src/SensorPipeline.cpp @@ -23,6 +23,24 @@ std::uint64_t nowNs() noexcept std::chrono::duration_cast( Clock::now().time_since_epoch()).count()); } + +// A test scaffold for the producer loop that allows for bursts of measurements, +// the idea is to _force_, from time to time, the producer to block on emplacing +// a measurement to a full queue +// TODO: It is the `PositionProducer` that is the test fake here, this `SensorPipeline` +// is supposed to be production. Yet this test scaffold is jammed in here. Find a +// decent way to _abstract_ this away so this "burstiness" can be removed from this +// file. +long producerEnqueueInterval() +{ + static constexpr long burstInterval = 1000; + static constexpr long burstOf = 300; + + static long count{0}; + + return count++ % burstInterval <= burstOf; +} + } // namespace SensorPipeline::SensorPipeline(std::size_t capacity) @@ -76,6 +94,7 @@ void SensorPipeline::producerLoop() { PositionProducer producer; + // Loop getting measurements until done (stopped) while (m_running.load()) { const weather::Position pos = producer.nextPosition(); @@ -89,6 +108,7 @@ void SensorPipeline::producerLoop() weather::AnyMeasurement msg(header, pos); + // busy loop until measurement successfully enqueued while (m_running.load()) { if (m_queue.try_enqueue(msg)) @@ -101,7 +121,7 @@ void SensorPipeline::producerLoop() ; } } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(producerEnqueueInterval())); } } From 6c3e213903250b4fab8ac533cc659ee2734a6b1e Mon Sep 17 00:00:00 2001 From: David Bakin Date: Wed, 24 Jun 2026 21:38:32 -0700 Subject: [PATCH 6/9] Parameterize SensorPipeline by producer/consumer intervals and provide straight and bursty intervals Signed-off-by: David Bakin --- CMakeLists.txt | 1 + Chapter7-SensorPipelines/CMakeLists.txt | 2 + .../include/BurstySensorPipelineIntervals.h | 32 ++++++++++++++ .../include/DefaultSensorPipelineIntervals.h | 19 +++++++++ .../include/SensorPipeline.h | 19 ++++++++- .../src/SensorPipeline.cpp | 42 ++++++++----------- Chapter7-SensorPipelines/src/main.cpp | 6 ++- 7 files changed, 95 insertions(+), 26 deletions(-) create mode 100644 Chapter7-SensorPipelines/include/BurstySensorPipelineIntervals.h create mode 100644 Chapter7-SensorPipelines/include/DefaultSensorPipelineIntervals.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 85aab94..0598314 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") -Wpedantic -Wconversion -Wshadow + -fno-rtti ) endif() diff --git a/Chapter7-SensorPipelines/CMakeLists.txt b/Chapter7-SensorPipelines/CMakeLists.txt index 6846e3c..42298de 100644 --- a/Chapter7-SensorPipelines/CMakeLists.txt +++ b/Chapter7-SensorPipelines/CMakeLists.txt @@ -10,6 +10,8 @@ add_executable(SensorPipelineDemo include/PositionProducer.h include/PositionConsumer.h include/SensorPipeline.h + include/BurstySensorPipelineIntervals.h + include/DefaultSensorPipelineIntervals.h src/SensorPipeline.cpp src/PositionConsumer.cpp src/PositionProducer.cpp diff --git a/Chapter7-SensorPipelines/include/BurstySensorPipelineIntervals.h b/Chapter7-SensorPipelines/include/BurstySensorPipelineIntervals.h new file mode 100644 index 0000000..838baca --- /dev/null +++ b/Chapter7-SensorPipelines/include/BurstySensorPipelineIntervals.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include "SensorPipeline.h" + +// A test scaffold for the producer loop that allows for bursts of measurements, +// the idea is to _force_, from time to time, the producer to block on emplacing +// a measurement to a full queue +static +SensorPipelineIntervals& getBurstyIntervals() +{ + static constexpr long burstInterval = 1000; + static constexpr long burstOf = 300; + static long count {0}; + + struct Bursty : public SensorPipelineIntervals + { + std::chrono::nanoseconds pollingInterval() const + { + return std::chrono::microseconds(count++ % burstInterval <= burstOf); + } + + std::chrono::nanoseconds blockedWaitingInterval() const + { + return std::chrono::microseconds(50); + } + }; + + static Bursty bursty {}; + return bursty; +} diff --git a/Chapter7-SensorPipelines/include/DefaultSensorPipelineIntervals.h b/Chapter7-SensorPipelines/include/DefaultSensorPipelineIntervals.h new file mode 100644 index 0000000..c3c196e --- /dev/null +++ b/Chapter7-SensorPipelines/include/DefaultSensorPipelineIntervals.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +#include "SensorPipeline.h" + + +static +SensorPipelineIntervals& getDefaultIntervals() +{ + struct Defaults : public SensorPipelineIntervals + { + std::chrono::nanoseconds pollingInterval() const { return std::chrono::microseconds(1000); } + std::chrono::nanoseconds blockedWaitingInterval() const { return std::chrono::microseconds(50); } + }; + + static Defaults defaults {}; + return defaults; +} diff --git a/Chapter7-SensorPipelines/include/SensorPipeline.h b/Chapter7-SensorPipelines/include/SensorPipeline.h index ed46af3..fbf7c91 100644 --- a/Chapter7-SensorPipelines/include/SensorPipeline.h +++ b/Chapter7-SensorPipelines/include/SensorPipeline.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -9,6 +10,8 @@ #include "AnyMeasurement.h" +class SensorPipelineIntervals; + // // A simple, fixed-topology pipeline: // Producer thread -> SPSC queue -> Consumer thread @@ -17,6 +20,9 @@ class SensorPipeline { public: explicit SensorPipeline(std::size_t capacity); // creates this "holder" but doesn't start work + explicit SensorPipeline(std::size_t capacity, + const SensorPipelineIntervals& producerIntervals, + const SensorPipelineIntervals& consumerIntervals); ~SensorPipeline(); SensorPipeline(const SensorPipeline&) = delete; @@ -25,7 +31,7 @@ class SensorPipeline void start(); // create pipeline (including its threads) and start flow void stop(); // _request_ work to end (does not block) void join(); // wait for completion of pipeline (blocks) and end threads (and resources) - // ...now SensorPipeline is safe to destruct + // ...now SensorPipeline is safe to destruct void status(std::ostream& os); @@ -39,8 +45,19 @@ class SensorPipeline std::thread m_consumerThread; std::atomic m_running { false }; + const SensorPipelineIntervals& m_producerIntervals; + const SensorPipelineIntervals& m_consumerIntervals; + Counter producer_enqueued; Counter producer_blocked; Counter consumer_blocked; Counter consumer_dequeued; }; + +struct SensorPipelineIntervals +{ + virtual std::chrono::nanoseconds pollingInterval() const = 0; + virtual std::chrono::nanoseconds blockedWaitingInterval() const = 0; + + virtual ~SensorPipelineIntervals() = default; +}; diff --git a/Chapter7-SensorPipelines/src/SensorPipeline.cpp b/Chapter7-SensorPipelines/src/SensorPipeline.cpp index d7f3cd2..fca49c4 100644 --- a/Chapter7-SensorPipelines/src/SensorPipeline.cpp +++ b/Chapter7-SensorPipelines/src/SensorPipeline.cpp @@ -12,6 +12,7 @@ #include "MeasurementTypes.h" // weather::Position, MeasurementHeaderV1, SourceId #include "PositionProducer.h" #include "PositionConsumer.h" +#include "DefaultSensorPipelineIntervals.h" namespace { @@ -24,30 +25,23 @@ std::uint64_t nowNs() noexcept Clock::now().time_since_epoch()).count()); } -// A test scaffold for the producer loop that allows for bursts of measurements, -// the idea is to _force_, from time to time, the producer to block on emplacing -// a measurement to a full queue -// TODO: It is the `PositionProducer` that is the test fake here, this `SensorPipeline` -// is supposed to be production. Yet this test scaffold is jammed in here. Find a -// decent way to _abstract_ this away so this "burstiness" can be removed from this -// file. -long producerEnqueueInterval() -{ - static constexpr long burstInterval = 1000; - static constexpr long burstOf = 300; - - static long count{0}; - - return count++ % burstInterval <= burstOf; -} - } // namespace SensorPipeline::SensorPipeline(std::size_t capacity) - : m_queue(capacity) + : SensorPipeline(capacity, getDefaultIntervals(), getDefaultIntervals()) { } +SensorPipeline::SensorPipeline(std::size_t capacity, + const SensorPipelineIntervals& producerIntervals, + const SensorPipelineIntervals& consumerIntervals) + : m_queue(capacity) + , m_producerIntervals(producerIntervals) + , m_consumerIntervals(consumerIntervals) +{ +} + + SensorPipeline::~SensorPipeline() { stop(); @@ -117,11 +111,11 @@ void SensorPipeline::producerLoop() break; } else { producer_blocked++; - std::this_thread::sleep_for(std::chrono::microseconds(50)); -; } + std::this_thread::sleep_for(m_producerIntervals.blockedWaitingInterval()); + } } - std::this_thread::sleep_for(std::chrono::milliseconds(producerEnqueueInterval())); + std::this_thread::sleep_for(m_producerIntervals.pollingInterval()); } } @@ -143,7 +137,7 @@ void SensorPipeline::consumerLoop() if (!m_queue.try_dequeue(msg)) { consumer_blocked++; - std::this_thread::sleep_for(std::chrono::microseconds(50)); + std::this_thread::sleep_for(m_consumerIntervals.blockedWaitingInterval()); continue; } consumer_dequeued++; @@ -159,8 +153,8 @@ void SensorPipeline::consumerLoop() } } - // Optional drain after stop (keeps output tidy) - std::cerr << "--Draining queue--\n"; + // Drain after stop to ensure all measurements are used and + // pipeline is emptied) while (true) { if (m_queue.try_dequeue(msg)) diff --git a/Chapter7-SensorPipelines/src/main.cpp b/Chapter7-SensorPipelines/src/main.cpp index 906f108..cfd48cc 100644 --- a/Chapter7-SensorPipelines/src/main.cpp +++ b/Chapter7-SensorPipelines/src/main.cpp @@ -3,13 +3,17 @@ #include #include "SensorPipeline.h" +#include "BurstySensorPipelineIntervals.h" +#include "DefaultSensorPipelineIntervals.h" using namespace weather; int main() { // "Capacity" is an initial sizing parameter for the SPSC queue. - SensorPipeline pipeline(/*capacity*/ 128); + SensorPipeline pipeline(128 /* capacity */, + getBurstyIntervals() /* producer intervals */, + getDefaultIntervals() /* consumer intervals */); pipeline.start(); From 30dfd4a1c86f50633016fa0c5ad847dd08d58c5e Mon Sep 17 00:00:00 2001 From: David Bakin Date: Thu, 25 Jun 2026 08:22:39 -0700 Subject: [PATCH 7/9] fix chapter numbering in Chapter 7 Signed-off-by: David Bakin --- Chapter7-SensorPipelines/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter7-SensorPipelines/README.md b/Chapter7-SensorPipelines/README.md index 00891d1..2c9f820 100644 --- a/Chapter7-SensorPipelines/README.md +++ b/Chapter7-SensorPipelines/README.md @@ -1 +1 @@ -This repository accompanies Chapter 8 of _Designing Deterministic Systems with Modern C++_. +This repository accompanies Chapter 7 of _Designing Deterministic Systems with Modern C++_. From fa3db47497ad7962dfdfe069043dd13d4e64b241 Mon Sep 17 00:00:00 2001 From: David Bakin Date: Thu, 25 Jun 2026 08:29:28 -0700 Subject: [PATCH 8/9] Rename old chapter 9 to new chapter 8 in code Signed-off-by: David Bakin --- CMakeLists.txt | 2 +- .../CMakeLists.txt | 12 ++++++------ .../README.md | 8 ++++---- .../include/BuildStatus.h | 0 .../include/Chapter8MeasurementFactory.h | 2 +- .../include/Chapter8RunLoops.h | 8 ++++---- .../include/LogEvent.h | 0 .../include/WeatherSystem.h | 6 +++--- .../include/WeatherSystemBuilder.h | 0 .../src/Chapter8MeasurementFactory.cpp | 4 ++-- .../src/Chapter8RunLoops.cpp | 12 ++++++------ .../src/WeatherSystem.cpp | 6 +++--- .../src/WeatherSystemBuilder.cpp | 2 +- .../src/main.cpp | 0 14 files changed, 31 insertions(+), 31 deletions(-) rename {Chapter8-SytemCompositionAndControl => Chapter8-SystemCompositionAndControl}/CMakeLists.txt (58%) rename {Chapter8-SytemCompositionAndControl => Chapter8-SystemCompositionAndControl}/README.md (73%) rename {Chapter8-SytemCompositionAndControl => Chapter8-SystemCompositionAndControl}/include/BuildStatus.h (100%) rename Chapter8-SytemCompositionAndControl/include/Chapter9MeasurementFactory.h => Chapter8-SystemCompositionAndControl/include/Chapter8MeasurementFactory.h (96%) rename Chapter8-SytemCompositionAndControl/include/Chapter9RunLoops.h => Chapter8-SystemCompositionAndControl/include/Chapter8RunLoops.h (87%) rename {Chapter8-SytemCompositionAndControl => Chapter8-SystemCompositionAndControl}/include/LogEvent.h (100%) rename {Chapter8-SytemCompositionAndControl => Chapter8-SystemCompositionAndControl}/include/WeatherSystem.h (91%) rename {Chapter8-SytemCompositionAndControl => Chapter8-SystemCompositionAndControl}/include/WeatherSystemBuilder.h (100%) rename Chapter8-SytemCompositionAndControl/src/Chapter9MeasurementFactory.cpp => Chapter8-SystemCompositionAndControl/src/Chapter8MeasurementFactory.cpp (95%) rename Chapter8-SytemCompositionAndControl/src/Chapter9RunLoops.cpp => Chapter8-SystemCompositionAndControl/src/Chapter8RunLoops.cpp (95%) rename {Chapter8-SytemCompositionAndControl => Chapter8-SystemCompositionAndControl}/src/WeatherSystem.cpp (89%) rename {Chapter8-SytemCompositionAndControl => Chapter8-SystemCompositionAndControl}/src/WeatherSystemBuilder.cpp (95%) rename {Chapter8-SytemCompositionAndControl => Chapter8-SystemCompositionAndControl}/src/main.cpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0598314..7e713e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ add_subdirectory(SetupChapter) add_subdirectory(Common) add_subdirectory(Chapter3-TypeErasure) add_subdirectory(Chapter7-SensorPipelines) -add_subdirectory(Chapter8-SytemCompositionAndControl) # note spelling error +add_subdirectory(Chapter8-SystemCompositionAndControl) add_subdirectory(Chapter9-IntegratingExternalInputs) add_subdirectory(Chapter10-FusionTiming) add_subdirectory(Chapter11-DeterministicFusionAndOutput) diff --git a/Chapter8-SytemCompositionAndControl/CMakeLists.txt b/Chapter8-SystemCompositionAndControl/CMakeLists.txt similarity index 58% rename from Chapter8-SytemCompositionAndControl/CMakeLists.txt rename to Chapter8-SystemCompositionAndControl/CMakeLists.txt index c258c3f..c7bb517 100644 --- a/Chapter8-SytemCompositionAndControl/CMakeLists.txt +++ b/Chapter8-SystemCompositionAndControl/CMakeLists.txt @@ -1,21 +1,21 @@ cmake_minimum_required(VERSION 3.16) -project(chapter9_system_demo LANGUAGES CXX) +project(chapter8_system_demo LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -add_executable(chapter9_demo +add_executable(chapter8_demo src/main.cpp src/WeatherSystem.cpp src/WeatherSystemBuilder.cpp - src/Chapter9RunLoops.cpp + src/Chapter8RunLoops.cpp include/WeatherSystem.h include/WeatherSystemBuilder.h - include/Chapter9MeasurementFactory.h - include/Chapter9RunLoops.h + include/Chapter8MeasurementFactory.h + include/Chapter8RunLoops.h ) -target_include_directories(chapter9_demo PRIVATE +target_include_directories(chapter8_demo PRIVATE include ../Common/include ../ThirdParty/readerwriterqueue diff --git a/Chapter8-SytemCompositionAndControl/README.md b/Chapter8-SystemCompositionAndControl/README.md similarity index 73% rename from Chapter8-SytemCompositionAndControl/README.md rename to Chapter8-SystemCompositionAndControl/README.md index d574a23..3abbbd2 100644 --- a/Chapter8-SytemCompositionAndControl/README.md +++ b/Chapter8-SystemCompositionAndControl/README.md @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT // Copyright (c) 2025 Autumnal Software -# Chapter 9 - System Controller (Snapshot) +# Chapter 8 - System Composition And Control (Snapshot) -This repository accompanies Chapter 9 of _Designing Deterministic Systems with Modern C++_. +This repository accompanies Chapter 8 of _Designing Deterministic Systems with Modern C++_. -This Chapter 9 demo is about system composition and control. +This Chapter 8 demo is about system composition and control. - Uses `std::thread` - No Boost.Asio @@ -18,7 +18,7 @@ This Chapter 9 demo is about system composition and control. This snapshot assumes the repository already provides: - `ThirdParty/readerwriterqueue` -- `ThirdParty/boost_asio_1_36_0` (not used in Chapter 9, but present for later chapters) +- `ThirdParty/boost_asio_1_36_0` (not used in Chapter 8, but present for later chapters) - `../Chapter7-ImprovedAnyMeasurement/include` containing: - `MeasurementTypes.h` - `AnyMeasurement.h` diff --git a/Chapter8-SytemCompositionAndControl/include/BuildStatus.h b/Chapter8-SystemCompositionAndControl/include/BuildStatus.h similarity index 100% rename from Chapter8-SytemCompositionAndControl/include/BuildStatus.h rename to Chapter8-SystemCompositionAndControl/include/BuildStatus.h diff --git a/Chapter8-SytemCompositionAndControl/include/Chapter9MeasurementFactory.h b/Chapter8-SystemCompositionAndControl/include/Chapter8MeasurementFactory.h similarity index 96% rename from Chapter8-SytemCompositionAndControl/include/Chapter9MeasurementFactory.h rename to Chapter8-SystemCompositionAndControl/include/Chapter8MeasurementFactory.h index 3fb4c8b..db6cd31 100644 --- a/Chapter8-SytemCompositionAndControl/include/Chapter9MeasurementFactory.h +++ b/Chapter8-SystemCompositionAndControl/include/Chapter8MeasurementFactory.h @@ -9,7 +9,7 @@ #include "AnyMeasurement.h" #include "MeasurementTypes.h" -namespace chapter9 +namespace chapter8 { using Clock = std::chrono::steady_clock; diff --git a/Chapter8-SytemCompositionAndControl/include/Chapter9RunLoops.h b/Chapter8-SystemCompositionAndControl/include/Chapter8RunLoops.h similarity index 87% rename from Chapter8-SytemCompositionAndControl/include/Chapter9RunLoops.h rename to Chapter8-SystemCompositionAndControl/include/Chapter8RunLoops.h index 9904efe..31e8ec1 100644 --- a/Chapter8-SytemCompositionAndControl/include/Chapter9RunLoops.h +++ b/Chapter8-SystemCompositionAndControl/include/Chapter8RunLoops.h @@ -9,7 +9,7 @@ #include "LogEvent.h" #include "readerwriterqueue.h" -struct Chapter9Stats +struct Chapter8Stats { std::atomic enqTempOk{0}; std::atomic enqPosOk{0}; @@ -27,10 +27,10 @@ struct Chapter9Stats -class Chapter9RunLoops +class Chapter8RunLoops { public: - Chapter9RunLoops(moodycamel::ReaderWriterQueue& inQ, + Chapter8RunLoops(moodycamel::ReaderWriterQueue& inQ, moodycamel::ReaderWriterQueue& logQ); void producer(const std::atomic& stop); @@ -41,5 +41,5 @@ class Chapter9RunLoops moodycamel::ReaderWriterQueue& m_inQ; moodycamel::ReaderWriterQueue& m_logQ; - Chapter9Stats m_stats; + Chapter8Stats m_stats; }; diff --git a/Chapter8-SytemCompositionAndControl/include/LogEvent.h b/Chapter8-SystemCompositionAndControl/include/LogEvent.h similarity index 100% rename from Chapter8-SytemCompositionAndControl/include/LogEvent.h rename to Chapter8-SystemCompositionAndControl/include/LogEvent.h diff --git a/Chapter8-SytemCompositionAndControl/include/WeatherSystem.h b/Chapter8-SystemCompositionAndControl/include/WeatherSystem.h similarity index 91% rename from Chapter8-SytemCompositionAndControl/include/WeatherSystem.h rename to Chapter8-SystemCompositionAndControl/include/WeatherSystem.h index ddd12fe..8850f0a 100644 --- a/Chapter8-SytemCompositionAndControl/include/WeatherSystem.h +++ b/Chapter8-SystemCompositionAndControl/include/WeatherSystem.h @@ -12,7 +12,7 @@ #include "LogEvent.h" #include "readerwriterqueue.h" -class Chapter9RunLoops; +class Chapter8RunLoops; class WeatherSystem { @@ -35,13 +35,13 @@ class WeatherSystem moodycamel::ReaderWriterQueue& inQueue() noexcept; moodycamel::ReaderWriterQueue& logQueue() noexcept; - Chapter9RunLoops& runLoops() noexcept; + Chapter8RunLoops& runLoops() noexcept; private: moodycamel::ReaderWriterQueue m_inQ; moodycamel::ReaderWriterQueue m_logQ; - Chapter9RunLoops* m_runLoops; + Chapter8RunLoops* m_runLoops; std::array&)>, ThreadCount> m_entries {}; std::array m_threads {}; diff --git a/Chapter8-SytemCompositionAndControl/include/WeatherSystemBuilder.h b/Chapter8-SystemCompositionAndControl/include/WeatherSystemBuilder.h similarity index 100% rename from Chapter8-SytemCompositionAndControl/include/WeatherSystemBuilder.h rename to Chapter8-SystemCompositionAndControl/include/WeatherSystemBuilder.h diff --git a/Chapter8-SytemCompositionAndControl/src/Chapter9MeasurementFactory.cpp b/Chapter8-SystemCompositionAndControl/src/Chapter8MeasurementFactory.cpp similarity index 95% rename from Chapter8-SytemCompositionAndControl/src/Chapter9MeasurementFactory.cpp rename to Chapter8-SystemCompositionAndControl/src/Chapter8MeasurementFactory.cpp index fb072be..83b72ad 100644 --- a/Chapter8-SytemCompositionAndControl/src/Chapter9MeasurementFactory.cpp +++ b/Chapter8-SystemCompositionAndControl/src/Chapter8MeasurementFactory.cpp @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Copyright (c) 2025 Autumnal Software -#include "Chapter9MeasurementFactory.h" +#include "Chapter8MeasurementFactory.h" -namespace chapter9 +namespace chapter8 { std::uint64_t to_ns(Clock::time_point t) noexcept { diff --git a/Chapter8-SytemCompositionAndControl/src/Chapter9RunLoops.cpp b/Chapter8-SystemCompositionAndControl/src/Chapter8RunLoops.cpp similarity index 95% rename from Chapter8-SytemCompositionAndControl/src/Chapter9RunLoops.cpp rename to Chapter8-SystemCompositionAndControl/src/Chapter8RunLoops.cpp index 7c5e745..8d3b18a 100644 --- a/Chapter8-SytemCompositionAndControl/src/Chapter9RunLoops.cpp +++ b/Chapter8-SystemCompositionAndControl/src/Chapter8RunLoops.cpp @@ -7,7 +7,7 @@ #include #include -#include "Chapter9RunLoops.h" +#include "Chapter8RunLoops.h" #include "MeasurementTypes.h" // @@ -39,7 +39,7 @@ static void updateMax(std::atomic& maxVal, } } -Chapter9RunLoops::Chapter9RunLoops( +Chapter8RunLoops::Chapter8RunLoops( moodycamel::ReaderWriterQueue& inQ, moodycamel::ReaderWriterQueue& logQ) : m_inQ(inQ) @@ -47,7 +47,7 @@ Chapter9RunLoops::Chapter9RunLoops( { } -void Chapter9RunLoops::producer(const std::atomic& stop) +void Chapter8RunLoops::producer(const std::atomic& stop) { using namespace std::chrono; @@ -112,7 +112,7 @@ void Chapter9RunLoops::producer(const std::atomic& stop) } } -void Chapter9RunLoops::consumer(const std::atomic& stop) +void Chapter8RunLoops::consumer(const std::atomic& stop) { using namespace std::chrono; @@ -150,7 +150,7 @@ void Chapter9RunLoops::consumer(const std::atomic& stop) updateMax(m_stats.latencyMaxNs, nowNs - rxNs); } - // No per-message logging in Chapter 9. + // No per-message logging in Chapter 8. } else { @@ -160,7 +160,7 @@ void Chapter9RunLoops::consumer(const std::atomic& stop) } -void Chapter9RunLoops::logger(const std::atomic& stop) +void Chapter8RunLoops::logger(const std::atomic& stop) { using namespace std::chrono; diff --git a/Chapter8-SytemCompositionAndControl/src/WeatherSystem.cpp b/Chapter8-SystemCompositionAndControl/src/WeatherSystem.cpp similarity index 89% rename from Chapter8-SytemCompositionAndControl/src/WeatherSystem.cpp rename to Chapter8-SystemCompositionAndControl/src/WeatherSystem.cpp index 185e804..3730858 100644 --- a/Chapter8-SytemCompositionAndControl/src/WeatherSystem.cpp +++ b/Chapter8-SystemCompositionAndControl/src/WeatherSystem.cpp @@ -2,12 +2,12 @@ // Copyright (c) 2025 Autumnal Software #include "WeatherSystem.h" -#include "Chapter9RunLoops.h" +#include "Chapter8RunLoops.h" WeatherSystem::WeatherSystem() : m_inQ(256) , m_logQ(64) - , m_runLoops(new Chapter9RunLoops(m_inQ, m_logQ)) + , m_runLoops(new Chapter8RunLoops(m_inQ, m_logQ)) { } @@ -59,7 +59,7 @@ moodycamel::ReaderWriterQueue& WeatherSystem::logQueue() noexcept return m_logQ; } -Chapter9RunLoops& WeatherSystem::runLoops() noexcept +Chapter8RunLoops& WeatherSystem::runLoops() noexcept { return *m_runLoops; } diff --git a/Chapter8-SytemCompositionAndControl/src/WeatherSystemBuilder.cpp b/Chapter8-SystemCompositionAndControl/src/WeatherSystemBuilder.cpp similarity index 95% rename from Chapter8-SytemCompositionAndControl/src/WeatherSystemBuilder.cpp rename to Chapter8-SystemCompositionAndControl/src/WeatherSystemBuilder.cpp index 56424f3..0463f28 100644 --- a/Chapter8-SytemCompositionAndControl/src/WeatherSystemBuilder.cpp +++ b/Chapter8-SystemCompositionAndControl/src/WeatherSystemBuilder.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2025 Autumnal Software #include "WeatherSystemBuilder.h" -#include "Chapter9RunLoops.h" +#include "Chapter8RunLoops.h" BuildStatus WeatherSystemBuilder::build(WeatherSystem& system) const { diff --git a/Chapter8-SytemCompositionAndControl/src/main.cpp b/Chapter8-SystemCompositionAndControl/src/main.cpp similarity index 100% rename from Chapter8-SytemCompositionAndControl/src/main.cpp rename to Chapter8-SystemCompositionAndControl/src/main.cpp From cac5cbbc57747835938b172aea8cab96f9dcbda2 Mon Sep 17 00:00:00 2001 From: David Bakin Date: Sat, 27 Jun 2026 09:47:10 -0700 Subject: [PATCH 9/9] Increase length of run of Chapter8 demo; remove an unneeded file Signed-off-by: David Bakin --- .../CMakeLists.txt | 1 - .../include/Chapter8MeasurementFactory.h | 21 --------- .../src/Chapter8MeasurementFactory.cpp | 44 ------------------- .../src/main.cpp | 6 ++- 4 files changed, 5 insertions(+), 67 deletions(-) delete mode 100644 Chapter8-SystemCompositionAndControl/include/Chapter8MeasurementFactory.h delete mode 100644 Chapter8-SystemCompositionAndControl/src/Chapter8MeasurementFactory.cpp diff --git a/Chapter8-SystemCompositionAndControl/CMakeLists.txt b/Chapter8-SystemCompositionAndControl/CMakeLists.txt index c7bb517..4881203 100644 --- a/Chapter8-SystemCompositionAndControl/CMakeLists.txt +++ b/Chapter8-SystemCompositionAndControl/CMakeLists.txt @@ -11,7 +11,6 @@ add_executable(chapter8_demo src/Chapter8RunLoops.cpp include/WeatherSystem.h include/WeatherSystemBuilder.h - include/Chapter8MeasurementFactory.h include/Chapter8RunLoops.h ) diff --git a/Chapter8-SystemCompositionAndControl/include/Chapter8MeasurementFactory.h b/Chapter8-SystemCompositionAndControl/include/Chapter8MeasurementFactory.h deleted file mode 100644 index db6cd31..0000000 --- a/Chapter8-SystemCompositionAndControl/include/Chapter8MeasurementFactory.h +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2025 Autumnal Software - -#pragma once - -#include -#include - -#include "AnyMeasurement.h" -#include "MeasurementTypes.h" - -namespace chapter8 -{ - using Clock = std::chrono::steady_clock; - - // Convert steady_clock time_point to a monotonic nanosecond tick count. - std::uint64_t to_ns(Clock::time_point t) noexcept; - - weather::AnyMeasurement make_temperature(double seed, Clock::time_point eventTime, Clock::time_point rxTime); - weather::AnyMeasurement make_position(double seed, Clock::time_point eventTime, Clock::time_point rxTime); -} diff --git a/Chapter8-SystemCompositionAndControl/src/Chapter8MeasurementFactory.cpp b/Chapter8-SystemCompositionAndControl/src/Chapter8MeasurementFactory.cpp deleted file mode 100644 index 83b72ad..0000000 --- a/Chapter8-SystemCompositionAndControl/src/Chapter8MeasurementFactory.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2025 Autumnal Software - -#include "Chapter8MeasurementFactory.h" - -namespace chapter8 -{ - std::uint64_t to_ns(Clock::time_point t) noexcept - { - return static_cast( - std::chrono::duration_cast(t.time_since_epoch()).count()); - } - - weather::AnyMeasurement make_temperature(double seed, Clock::time_point eventTime, Clock::time_point rxTime) - { - weather::MeasurementHeaderV1 h; - h.eventTime = to_ns(eventTime); - h.rxTime = to_ns(rxTime); - h.source = weather::SourceId::Unknown; - h.flags = 0; - // kind is set by AnyMeasurement via MeasurementKindOf - - weather::Temperature t; - t.value = 20.0 + seed; - - return weather::AnyMeasurement(h, t); - } - - weather::AnyMeasurement make_position(double seed, Clock::time_point eventTime, Clock::time_point rxTime) - { - weather::MeasurementHeaderV1 h; - h.eventTime = to_ns(eventTime); - h.rxTime = to_ns(rxTime); - h.source = weather::SourceId::Unknown; - h.flags = 0; - - weather::Position p; - p.lat = 43.0 + seed * 0.0001; - p.lon = -77.0 + seed * 0.0001; - p.alt = 150.0; - - return weather::AnyMeasurement(h, p); - } -} diff --git a/Chapter8-SystemCompositionAndControl/src/main.cpp b/Chapter8-SystemCompositionAndControl/src/main.cpp index 7b2c738..840369d 100644 --- a/Chapter8-SystemCompositionAndControl/src/main.cpp +++ b/Chapter8-SystemCompositionAndControl/src/main.cpp @@ -46,8 +46,12 @@ int main(int argc, char** argv) lock_memory(); // After construction, before execution } + + const auto deviceRunLength{std::chrono::seconds(15)}; + + system.start(); - std::this_thread::sleep_for(std::chrono::seconds(5)); + std::this_thread::sleep_for(deviceRunLength); system.stop(); system.join();