
Explore how a process owns memory and resources, while threads share that memory but have their own stacks, and learn how the OS uses PCB and TCB to manage them.
Explore the graphics section of video 1.1, showing how code tells the story of life in the workplace, with focus on tasks and deadlines.
Multithreading lets a program perform multiple tasks concurrently within one process, speeding execution on multi-core CPUs, improving CPU utilization, responsiveness, and shared memory within the same process.
Explore the graphics module by examining each element separately to understand how every detail shifts the balance of the final product, illustrating that code, like life, never exists alone.
Explore why every thread has its own stack in POSIX multithreading, preventing stack corruption and race conditions by keeping local variables isolated.
Explore how threads share and allocate space in posix multithreading, using safe and derivative space analogies to illustrate thread obstacles and the limits of code.
Learn how race conditions occur when multiple threads access shared data without synchronization, causing data corruption or incorrect results, and how mutexes, semaphores, and atomic operations prevent them.
Explore the race dynamics, focusing on timing, rules, and the central resource and date. See how a single mistake flips the outcome, as the code and video reveal the lesson.
Explore why multithreading outperforms multiple processes like fork or clone, offering speed and memory efficiency through shared memory and faster creation, while noting race conditions and when processes are preferable.
Learn how POSIX threads enable multi-threading in Unix by creating new threads with pthread_create (four arguments: the thread id, attributes, the thread function, and its argument), and synchronize with pthread_join.
Explore how threads terminate in POSIX programs: returning from a thread function, pthread_exit, and thread cancellation, and how process termination versus main thread exit affects remaining threads and joinability.
Join POSIX threads to wait for a specific thread to finish, reclaim resources, and retrieve return values, while understanding joinable vs detached threads.
Explore POSIX thread detaching, distinguishing joinable and detached threads, how to detach or create detached threads, and why joining a detached thread is invalid.
Explore POSIX thread cancellation, including cancellation state and type, deferred cancellation, cleanup handlers, cancellation points, and safe resource cleanup to prevent leaks and deadlocks.
Learn atomic programming and race-condition prevention using atomic operations, mutexes, and hardware or GCC built-ins, while avoiding volatile and safely updating a shared counter in multi-threaded code.
Explore POSIX multithreading with mutex locks to prevent race conditions when multiple threads update a shared counter, using pthread mutex lock and unlock for correct increments.
Master posix mutexes for safe shared resource access, covering static vs dynamic locks, trylock, and timed lock to prevent deadlocks.
This lecture explains deadlocks in multithreading—mutual exclusion, hold and wait, no preemption, and circular wait—and offers fixes like fixed-order locking and banker's algorithm.
Explore POSIX reader-writer locks, enabling multiple concurrent readers with a single writer, using read and write locks, initialization, destruction, and scenarios where reads predominate over writes.
Configure mutex attributes to tailor lock behavior, enabling recursive locks, process sharing, and priority inheritance for robust multi-threaded synchronization.
Explore how condition variables coordinate threads with a mutex to wait for conditions, using pthread cond wait, signal, and broadcast, including timed waits and preventing missed signals and spurious wakeups.
Master the producer-consumer problem by using a mutex and condition variables to coordinate a shared buffer, avoid deadlocks and race conditions, and ensure fair scheduling for multiple threads.
Learn to implement spinlocks for ultra-fast, low-latency locking using pthread spin APIs, balancing busy-wait benefits against potential CPU waste and fairness concerns in real-time and kernel contexts.
Learn how barriers synchronize multiple threads using POSIX threads, ensuring all threads reach a checkpoint before continuing, preventing race conditions in parallel computing and simulations.
Understand thread safety to prevent data corruption when multiple threads access shared resources. Use mutexes and read-write locks to stop race conditions, deadlocks, and priority inversion, coordinating readers and writers.
Identify re-entrant versus non-re-entrant functions in POSIX multithreading, and learn safe approaches like thread local storage, mutexes, and f lock file for thread-safe I/O.
Learn how to implement per-thread storage with tsd APIs in posix threads, creating unique keys, storing and retrieving thread-specific data, using destructors, and ensuring automatic cleanup.
Explore the thread-specific data API to give each thread its own strerror buffer, preventing data races, avoiding locks, and automatically cleaning up memory as threads exit.
Explore thread local storage and how Linux imposes thread limits, then implement tlc with pthread keys or __thread and thread_local, including dynamic per-thread data and destructor cleanup.
Discover how each thread gets its own stack to store locals and return addresses, and how to configure default and custom sizes with guard pages and ASan.
Explore how signals interact with threads, including process-wide versus thread-specific behavior, and learn safe handling with a dedicated signal-handling thread using pthreads and sigaction.
Explain the difference between user space and kernel space, why isolation protects the system, and how system calls bridge the two worlds, with context switches and performance implications.
Explore the history of futex, a hybrid Linux synchronization that runs most locks in userspace and uses the kernel only when contention occurs, reducing kernel mode transactions.
Differentiate the fast path as the highway of execution, optimized for speed. Apply fast-path techniques like vdso and mmap to avoid calls, minimize locks, and bypass kernel networking.
Explore futex system call API for fast userspace synchronization in Linux, keeping most work in user space and only invoking the kernel when contention arises to boost performance.
Implement a basic mutex from scratch using Linux futexes, atomic operations, and futex wait/wake wrappers to demonstrate low-level locking and thread synchronization in C.
Implement a condition variable from scratch using futex, atomic operations, and system calls. Workers wait on the condition with a mutex; a signal thread wakes them, mirroring posix pthreads.
Explore efficient futex wake strategies for POSIX multithreading: avoid thundering herd, apply adaptive wakeups, use bitset and priority-based wakeups, and ensure real-time scheduling to prevent priority inversion and improve scalability.
Explore kernel-level optimizations of futex synchronization in Linux, including userspace fastpath, kernel slow path handling, and efficient wakeups via hashing, wake queues, and adaptive scheduling.
Explore futex and vertex hashing to manage contention by hashing vertex wait queues into buckets, enabling fastpath locking and wakeups with minimal kernel overhead.
In today’s computing world, concurrency is no longer optional — it’s essential. Modern applications must be fast, responsive, and capable of handling multiple tasks at once. This course is designed to give you a deep, practical understanding of multithreading programming in C using POSIX threads (pthreads) and futex, the powerful Linux system call for user-space synchronization.
Whether you're a systems programmer, embedded developer, Linux enthusiast, or computer science student, this course will walk you through every essential concept you need — starting from the basics and building up to low-level, high-performance techniques used in real-world software.
You'll begin by exploring the difference between processes and threads, understand why multithreading is more efficient, and learn how to create, manage, and terminate threads safely. From there, we’ll dive into synchronization tools like mutexes, condition variables, spinlocks, barriers, and advanced topics such as deadlocks, thread-local storage, reentrant functions, and thread safety.
In the second half of the course, you’ll learn how to use futex (Fast Userspace Mutex) — a Linux kernel mechanism for fast, scalable thread synchronization. We’ll explore futex APIs, fast vs. slow paths, kernel-level optimizations, and how futex is used under the hood by libraries like glibc and pthreads.
You’ll also analyze memory layout, thread stacks, how signals behave in multithreaded environments, and the difference between user and kernel space when working with threads.
By the end of this course, you’ll be able to write robust, thread-safe, and high-performance multithreaded applications in C — with a deep understanding of what’s happening behind the scenes at the kernel level.