Textbook: Operating Systems: Three Easy Pieces by Remzi H. Arpaci-Dusseau and Andrea C. Arpaci-Dusseau. Free online, you can also order a paper copy for a nominal fee.
Week Lectures/Readings Examples
1 External content
OPTIONAL CONTENT! An excellent (and Free) Computer Architecture course for those who are interested

IDE Setup
Install Ubuntu Linux using Virtual Box(Running a Mac with a M 1/2/3 chip? Use UTM instead of Virtual Box. Its virtual machines are compatible with the Mn architecture). Be sure to give the linux VM as much memory and CPUs as you can
Install g++ on Linux
Install Eclipse CDT on Linux

Quick Reference
C++ reference Card
Eclipse Shortcut Keys I use

Linux and Git tutorials
Linux tutorial
Another Linux tutorial
Git - the simple guide
Git and Linux demo notes

Lectures
Course Intro
Computer Architecture

Please read
Chapter 2 : Introduction to Operating Systems
2 External content
Operating System Interrupts Interrupt types, CPU Execution mode (Supervisor or User), Interrupt process flow

Lectures
Tangent: The PC boot process
Operating System Overview
Intro Paging example
Please read
Chapter 4 : Processes
Chapter 5 : Process API - fork(), wait(), exec() in unix plus a bit of linux command line
Chapter 6 : Direct Execution
3 External content
Optional: Introduction To Unix Signals Programming
Difference between fork() and exec()

Lectures
Interrupts
Process Description and Control
Please read Chapter 7: CPU Scheduling
and Chapter 8: The Multi-Level Feedback Queue
and Chapter 9: Scheduling: Proportional Share

4 External content
Process Scheduling Overview Very good!

Lectures
Process Scheduling
Please read Chapter 13: The Abstraction: Address Space
Please see, Chapter 14, Interlude: Memory API, just this 1/2 page "Aside: Why No Memory is Leaked Once Your Process Exits"
and Chapter 15: Mechanism: Address Translation
and Chapter 16: Segmentation
5 Lectures
Virtual Memory
Please read:
Chapter 18: Paging Introduction
Chapter 19: Paging: Faster Translations (TLBs)
Chapter 20: Paging: Smaller Tables
6,7,8 Lectures
Paging
Simple page table examples
Translation Lookaside Buffer (TLB)
Reducing the size of page tables
Examples: Multilevel Page tables How to drastically reduce the size of page tables ( essential especially for 64 bit systems)

Test,3/12/26. Includes everything above and project 2.
The test will be given to you on paper.
You may bring 1 sheet of paper with notes on both sides if you like. No other resources are allowed.


Please read Chapter 21: Beyond Physical Memory: Mechanisms
and Chapter 22: Beyond Physical Memory: Policies
9,10 External content
Please read Chapter 26: Concurrency: An Introduction
(Advanced) C++11 threads, affinity and hyperthreadingExcellent! relates C++ threads to processor hardware

Atomics Useful BUT can only synchronize 1 C++ operation at a time.
Lectures
Threads, an Introduction
Threads, Race conditions, critical sections, atomicsA multithreaded introduction
Takeaways:
  • Threaded applications can be proven incorrect, but not correct since you cant control the scheduler. Therefore testing is not as helpful. Your only defense is to write perfect code, to do this there are some rules to follow;
  • If you start a thread (thread t1(fun)) you must wait for it to finish (t1.join())!
  • Never, ever rely on knowledge of system behavior to predict thread run order! You cant tell! (see Thread_Race_Condition)
  • Learn to identify minimal critical sections. You want them to be as small as possible since only 1 thread can be in the critical section at a time, the others block and wait.
  • To identify critical sections, start by finding all variables that multiple threads can access. This includes all globals, heap based variables that multiple threads are aware of, and all non-threadsafe API's used (like cout)
  • Are these globals accessed by more than 1 thread? You probably have critical sections that need protection (synchronization).
  • the exception to this rule is a shared variable that is only read, never written. BUT the very first time it's written it needs protection (synchronization) on every read and write
  • Atomic classes are great, IFF you have a single line critical section. For multiple lines, you need a mutex (coming next)
Single thread demo Use disassembly view to see that each c++ statement is equivelent to multiple assembly instructions. An interrupt can be serviced after any assembly instruction, which may be in the middle of a C++ instruction
Problems that threads can cause Running several threads, each reading and writing a global will cause unpredictable results. Demo using an atomic variable for a simple (but not generalizable to blocks of code>1 line) solution
Thread Race Condition
10,11,12 External content
Please read Chapter 28: Locks
Please read Chapter 32, Common Concurrency Problems - pay attention to Deadlock and the section entitled 'Conditions for Deadlock' (see below)
Four conditions need to hold for a deadlock to occur:
  • Mutual exclusion: Threads claim exclusive control of resources that they require (e.g., a thread grabs a lock).
  • Hold-and-wait: Threads hold resources allocated to them (e.g., locks that they have already acquired) while waiting for additional resources (e.g., locks that they wish to acquire).
  • No preemption: Resources (e.g., locks) cannot be forcibly removed from threads that are holding them.
  • Circular wait: There exists a circular chain of threads such that each thread holds one or more resources (e.g., locks) that are being requested by the next thread in the chain.
Lectures
Mutexes
  • Mutexes are almost certainly going to be global variables (they will NOT be local variables)
  • Mutexes function as a traffic cop, they allow 1 thread in a critical section at a time(others threads are blocked)
  • Prefer a lock_guard over a raw mutex since it automatically unlocks when it goes out of scope
  • To use: Identify minimal critical sections, then wrap critical section with an auto unlocking lock_guard
Mutex Lecture notes.
Thread Ticket Agent Slides Goes with project to the right

Deadlock Rule of thumb: If you are using 2 or more synchronization objects, then you should always aquire them in the same order. If you break this rule and some threads aquire in different order then your code is prone to deadlock.
Deadlock Lecture notes.

Test 2, 4/16/26. Includes everything from previous test thru week 13 and project 3. The test will be given to you on paper.
You may bring 1 sheet of paper with notes on both sides. No other resources are allowed.
You should know;
  • how to identify and protect critical sections in a multi threaded program
  • how to maximize concurrency in a multithreaded program. For example, given 2 unrelated critical sections, you can protect each with a different mutex, and thus have 2 different threads executing in each critical section at the same time.
  • how to recognize and prevent deadlock
  • how to use mutexes in an exception prone environment (use a lock_guard that automatically unlocks)

Fix this non threadsafe code, here is the Solution
Stopping a thread Cleanly
A spinlock DEMO Do not use! Works but spikes CPU usage for all threads waiting for the lock!
Mutexes to synchronize threads Using a mutex to synchronize critical sections (as in multiple lines of code).
mutex_lock_guard_sleep_for_yield Using a lock_guard to autounlock a mutex once the guard goes out of scope. Also how to yield a threads timeslice or sleep the amount of time defined by std::chrono..
Simple Deadlock examples Very simple examples of how deadlock can occur
A slightly more complex deadlock example

Thread ticket agent - in class lab
Recursive_mutex A locking object that can be recursively locked (as long as you have 1 unlock() for every lock()). This added functionality typically makes it harder to keep track of locked regions when designing your application.
13 External content
Please read Chapter 30, Condition Variables

What if you want thread 1 to wait until thread 2 says go?
You cannot do this with just a mutex unless you use an ineffecient busy wait. Condition Variables solve this problem.

Condition Variables, definition and sample code article
Recursive Locks portion only This guy writes excellent C++ tutorials

Lectures
Condition Variables Demonstration slides
Producer Consumer, A common programming task Outline and solution flow.

Simple Condition VariablesOrdering thread operations. Signaling between threads using a mutex a condition variable and a unique_lock
Simple Condition Variables>What happens when you do not put cv.wait(...) in a while loop. (BTW you must always put cv.wait(...) in a while loop!)
Making all threads start at the same time using Condition Variables All threads wait but there is still a problem with synchronizing the cout and i
Simple producer consumer problem. Producer signals consumer.Single Producer, Single Consumer: Producer produces as fast as it can and notifies consumer, consumer consumes as fast as it can. Demoes effecient 1 way thread communication. Consumer will exit when global variable bDone is true and global count, gCount, of produced objects is 0. Can have multiple consumers.
Producer consumer problem using mutex and condition variables Single Producer, Multiple Consumers
Complex producer consumer problem, Producer signals consumer and vice versaProducer produces one then notifies consumer, consumer consumes one then notifies producer. Demoes effecient 2 way thread communications. Consumer will exit when global variable bDone is true and global count, gCount, of produced objects is 0.