Exercise 1: Manually Interleaving Three Programs — Possible Solution ==================================================================== THE TEST ------------------------------ def prog(name, n): total = 0 for i in range(n): print(f"{name}: step {i}") total += i yield total gens = [prog('A', 3), prog('B', 3), prog('C', 3)] active = list(gens) while active: still = [] for g in active: try: next(g) still.append(g) except StopIteration: pass active = still RESULT ------------------------------ real interleaving pattern for 3 programs: ABCABCABC The real printed output cycles cleanly through A, B, and C, one step at a time each, repeating exactly three times (matching each program's own 3-step length). WHY THE SAME TECHNIQUE GENERALIZES CLEANLY ------------------------------ Finding 3's own two-program version alternated between exactly two fixed generator objects. This version instead keeps a LIST of currently-active generators and walks the whole list once per round, calling next() on each one in turn. A program that finishes early (raises StopIteration) is simply left out of the `still` list for every future round -- it stops appearing in the interleaving, but nothing about the other programs' own execution is disturbed. This is a genuinely more realistic shape than the original two-program version: a real kernel manages an arbitrary, changing number of active processes, not always exactly two. WHY THIS MATTERS FOR WHAT COMES LATER ------------------------------ This "walk a list, skip anything that's finished" shape is precisely what a real round-robin scheduler (Chapter 7) needs to do -- maintain a queue of runnable processes, give each one a turn in order, and correctly remove a process from the queue once it terminates, without disturbing the fairness of everyone else's own turn. WHY THIS WORKS AS AN ANSWER ------------------------------ Extending Finding 3's own fixed two-program interleaving to a variable-length list of three programs -- and confirming the real output still shows a clean, correctly-ordered cycle -- demonstrates the underlying technique isn't a two-program-only trick, but a genuinely general pattern for managing any number of runnable programs at once.