.. include:: Agenda: (Linux/Zephyr) Systems Programming With C++ =================================================== Three days of systems programming, interwoven with select C++ topics. .. topic:: Material Topics below taken from * :doc:`/trainings/material/soup/linux/sysprog/index` * :doc:`/trainings/material/soup/cxx/cxx11/index` * :doc:`/trainings/material/soup/cxx/cxx03/index` .. contents:: :local: Why Use An RTOS? ---------------- .. topic:: TODO (Trainer) Write a +/- list :-) * + Scheduling instead of interrupts, see below * + Well defined realtime semantics * Discuss +/- list * Query audence's understanding of "realtime" Multithreading, And All Its Consequences ---------------------------------------- .. _2026-XX-XX--CXX-SysProg: Intro: Load-Modify-Store Conflict ................................. Following :doc:`/trainings/material/soup/python/advanced/multithreading/mutex`, hack a quick intro to the mother of all race conditions. "Quick" because we use ``std::thread`` and two lambdas. One lambda to count up a global ``int`` variable 10_000_000 times, another to count it down 10_000_000, being puzzled that they *don't meet at 0*. POSIX Threads: Creation And Lifetime .................................... .. topic:: Material * :doc:`/trainings/material/soup/linux/sysprog/posix-threads/010-introduction/topic` * :doc:`/trainings/material/soup/linux/sysprog/posix-threads/020-lifecycle/topic` How are threads created, and what tuning knobs exist to control their behavior - *attributes*. Provoke a discussion about realtime scheduling, and its hazards (priority inversion). Defer the solution (:ref:`priority inheritance `) until later in the threads section. Lets largely disregard thread termination (it is unlikely that there is a usecase for it), in favor of a short discussion. * It is a complex topic, despite the simple API * The effect of *cancellation* might have unpleasant side effects when the thread is in the middle of critical section. .. topic:: TODO (Trainer) Present possible attributes in a table form, most importantly: * https://man7.org/linux/man-pages/man3/pthread_attr_setschedparam.3.html * https://man7.org/linux/man-pages/man3/pthread_attr_setguardsize.3.html * https://man7.org/linux/man-pages/man3/pthread_attr_setstack.3.html, https://man7.org/linux/man-pages/man3/pthread_attr_setstackaddr.3.html, https://man7.org/linux/man-pages/man3/pthread_attr_setstacksize.3.html Mutual Exclusion ................ First, lets refactor the outcome of :ref:`2026-XX-XX--CXX-SysProg` to use ````, making thread creation a little less easy (which is good). Atomics, GCC Atomic Builtins, Zephyr Atomics ```````````````````````````````````````````` .. topic:: Material * :doc:`/trainings/material/soup/cxx/cxx11/multithreading/040-locking-atomics/atomics` * :doc:`/trainings/material/soup/c/080-advanced-language-features/020-atomic/topic` * https://docs.zephyrproject.org/latest/doxygen/html/sys_2atomic_8h_source.html Modify *load-modify-store* to use C++ atomics; this is simplest. .. topic:: TODO (Trainer) Create a table where the most important primitives are presented, starting with ``__sync_fetch_and_add()`` (and its equivalents in either domain). And Volatile? ````````````` Why ``volatile`` is of no use? There's that same question in :doc:`/trainings/material/soup/c/080-advanced-language-features/020-atomic/topic`, elaborate on it. Essentially: * ``volatile`` prevents the *compiler* from optimizations/reordering * CPUs are much more intelligent than you might think and *reorder* memory accesses internally Mutexes ``````` .. topic:: Material * :doc:`/trainings/material/soup/cxx/cxx11/multithreading/040-locking-atomics/mutex` * :doc:`/trainings/material/soup/cxx/cxx11/multithreading/040-locking-atomics/scoped-locking` * :doc:`/trainings/material/soup/linux/sysprog/posix-threads/040-mutex/topic` * :doc:`/trainings/material/soup/cxx/cxx11/multithreading/040-locking-atomics/scoped-locking` Usecase For A Mutex ||||||||||||||||||| * Modify *load-modify-store* to *not* use atomics to protect the integer * Replace the integer with a ``std::list`` * Have two threads hammer on the poor list until crashes * |longrightarrow| Like load-modify-store, list manipulation is also a sequence of non-atomic operations (pointer bending) that may interleave and produce unwanted outcome * |longrightarrow| ``std::atomic`` is of no use at a higher level Mutex Intro ||||||||||| * Introduce a ``std::mutex`` into the code, right next to the list, as a second global variable which is acquired/released by the user * |longrightarrow| Not so pretty * Encapsulate the list *and* its lock into a surrounding class, and provide *methods* that guarantee thread safety Scoped Locking |||||||||||||| * Imagine premature ``return``, or an exception thrown in the middle of the critical section * Use ``std::scoped_lock<>`` .. topic:: TODO (Trainer) * In :doc:`/trainings/material/soup/cxx/cxx11/multithreading/040-locking-atomics/scoped-locking`, explain ``std::scoped_lock<>`` instead of ``std::lock_guard<>`` POSIX Mutexes ||||||||||||| .. topic:: Material * :doc:`/trainings/material/soup/linux/sysprog/posix-threads/040-mutex/topic` * Modify *The Program* to use ``pthread_mutex_t`` * Write a mutex class myself * Write a straightforward scoped lock myself * Explain mutex types (:ref:`pthread-mutex--types`), having fun with the ``PTHREAD_MUTEX_RECURSIVE`` shithouse analogy Spinlocks ||||||||| .. topic:: TODO (Refinement) * Are there usecases for a spinlock? * https://docs.zephyrproject.org/latest/doxygen/html/spinlock_8h.html Discussion: * Share data between IRQ and thread context * IRQ must not sleep Deadlock Scenario: Locking Mutexes In Undefined Order ||||||||||||||||||||||||||||||||||||||||||||||||||||| .. topic:: TODO (Refinement) * Should we? `Dining Philosophers `__ * Write a braindead program: two threads, two mutexes * |longrightarrow| works most of the time * Introduce an artificial race (most races happen so infrequently that three days wont suffice to see them) Deadlock Scenario: Priority Inversion ||||||||||||||||||||||||||||||||||||| .. topic:: Material * :doc:`/trainings/material/soup/linux/sysprog/scheduling/realtime-api` * :ref:`priority-inversion` * :doc:`/trainings/material/soup/linux/sysprog/scheduling/mars-pathfinder` * Given three threads with different hard realtime priorities * Running on a single CPU, ideally (multicore is way more subtle) |longrightarrow| for demo, use `taskset `__ * Make them lockup and explain how an unrelated medium priority thread can prevent a high priority thread from running * |longrightarrow| *Inversion* Communication (POSIX Condition Variables) ......................................... .. topic:: Material * :doc:`/trainings/material/soup/linux/sysprog/posix-threads/060-condition-variable/topic` Motivation `````````` * Queue/FIFO class with two ends * Producer and consumer threads on either end * No locking * |longrightarrow| crashes obviously Locking ``````` * Add a mutex to prevent races * |longrightarrow| What if queue full/empty? Enter Condition Variable ```````````````````````` .. topic:: Material * :doc:`/trainings/material/soup/linux/sysprog/posix-threads/060-condition-variable/topic` * Discuss *lost wakeup bug* * Seeing queue empty, a thread has to go to sleep, in order to wait for elements to become available * |longrightarrow| An element might appear right *after* the thread has seen empty, and *before* sleep * Implement wait conditions on either side, discussing matters as we go (``pthread_cond_wait()``, ``pthread_cond_signal()``) * Discuss `spurious wakup ` Optional: C++ Memory Model .......................... .. topic:: Material * :doc:`C++ memory model ` This is about multiprocessor memory visibility, and how C++ atomics (and likely any atomics) can be used to achieve lock-free synchronization/communication. A very good a-ha for those interested. .. topic:: TODO Discuss applicability Threading Alternative: Event Driven Programming ----------------------------------------------- .. topic:: Material * https://docs.zephyrproject.org/latest/kernel/services/polling.html * :doc:`/trainings/material/soup/linux/sysprog/eventloop/problem/index` * :doc:`/trainings/material/soup/linux/sysprog/eventloop/poll/index` * :doc:`/trainings/material/soup/linux/sysprog/eventloop/poll-cpp/index` * :doc:`/trainings/material/soup/linux/sysprog/eventloop/exercise-commit-rollback/index` * Maybe have a short look into Python's ``asyncio`` framework. Maybe only after we have looked into threading. Following the above material (loosely), hack together something that would work on Zephyr. * A `Zephyr kernel message queue `__ to feeds data into the program * Another message queue that can trigger commit/rollback .. topic:: TODO (Trainer) * For Linux, implement something that resembles the API of, say, a Zephyr kernel message queue (use a :doc:`POSIX message queue ` for this) * With this, craft an event-loop implementation that looks like `the example from Zephyr `__ .. topic:: TODO (Refinement) Can we come up with a more real-life scenario? C++ --- Smart Pointers, Move Semantics, And Perfect Forwarding ...................................................... .. topic:: Material * :doc:`/trainings/material/soup/cxx/cxx11/smart-pointers/index` * :doc:`/trainings/material/soup/cxx/cxx11/rule-of-5/topic` * :doc:`/trainings/material/soup/cxx/cxx11/move/index` * :doc:`/trainings/material/soup/cxx/cxx11/perfect-forwarding/topic` * Short overview of :doc:`smart pointers in C++ `, knowing that we'll never allocated anything that we have to take ownership of (``std::unique_ptr`` usage requires a bit of move-understanding, so this is a good intro) Switch to a straightforward ``String`` class, like in :doc:`/trainings/material/soup/cxx/cxx11/move/livehack-string-move`, and begin a deeper dive into C++'s braindead pitfalls. * :doc:`/trainings/material/soup/cxx/cxx11/rule-of-5/topic`, including *move*. There is a separate :doc:`slide deck on move here `. * Only because it looks syntactically like move, but is a completely different thing: :doc:`/trainings/material/soup/cxx/cxx11/perfect-forwarding/topic` .. topic:: TODO (Refinement) Live hacking: * Come up with a proper Zephyr *move* usecase. Kernel object wrappers for, say, ``k_msgq``, to prevent copy. Living Without A Heap ..................... .. topic:: TODO (Trainer) More material: * Overloading the ``new`` operator * Placement new * https://en.cppreference.com/cpp/memory/polymorphic_allocator Advanced Flexibility Techniques (Design Patterns?) .................................................. .. topic:: Material * :doc:`/trainings/material/soup/cxx/cxx-design-patterns/index` * :doc:`/trainings/material/soup/cxx/cxx03/inheritance-oo-design/index` * :doc:`/about/site/work-in-progress/fh-joanneum/2024/ss/2026-05-11` * :doc:`/trainings/material/soup/cxx/cxx11/drafts/embedded-problems/virtual-vs-nonvirtual` * Focus on *dependency injection*, resp. *strategy pattern* * C++ "interfaces": *one* use of the C++ ``virtual`` keyword * Strategy (Dependency Injection) * *Builder pattern*: given a pile of related (via interfaces, Strategy) classes, how to best build a bigger thing of it .. topic:: TODO (Refinement) * Discuss applicability * Come up with a in-company live-hacking scenario where decoupling is in order Miscellaneous ............. The rest that does not fit anywhere: * :doc:`/trainings/material/soup/cxx/cxx11/lambda/index` * ``std::function`` resp. inplace functions https://github.com/WG21-SG14/SG14/blob/master/SG14/inplace_function.h * :doc:`/trainings/material/soup/cxx/cxx11/ranges/index` * :doc:`/trainings/material/soup/cxx/cxx11/concepts/index` * Show creative ``auto`` usage: *Abbreviated function templates* (with concepts :-) ) .. topic:: TODO (Refinement) * Applicability * Live-hacking scenarios