skip to content

Concurrency

Doing more than one thing at a time and still being correct: threads and processes, locks and other primitives, the races and deadlocks they exist to prevent, memory models, async models, and parallel work distribution. Interviews lean hard on this area because concurrency bugs are the ones that survive testing.

part ofComputer science fundamentalsoverview, primer and where to startread it →
on this pageshow

explore

questions

248 · 10 sections

What is the difference between a process and a thread, and what does it actually mean to say that each process has its own address space?

level: juniorimportance: must knowfreq 85%
basics
~20 s

A process owns an isolated address space and OS resources; threads are execution contexts inside one process that share that memory. Each thread has its own stack, registers and program counter. Separate processes cannot touch each other's memory and must use explicit inter-process communication.

open as a page

Explain the difference between preemptive and cooperative scheduling of concurrent tasks, and what each model demands from the code being scheduled.

level: juniorimportance: must knowfreq 68%
basics
~20 s

Under preemptive scheduling a timer interrupt lets the scheduler suspend a task at almost any instruction and run another. Under cooperative scheduling a task runs until it voluntarily yields. Preemption guarantees progress for everyone; cooperation is cheaper and predictable but one non-yielding task blocks all others.

open as a page

Concurrency runtimes map the threads a program creates onto the threads an operating-system kernel actually schedules. Explain the 1:1, N:1 and M:N mappings, and what each one costs you.

level: juniorimportance: must knowfreq 58%
basics
~20 s

Three mappings of program threads onto kernel-scheduled threads. 1:1 — each program thread is a kernel thread: real parallelism, but costly. N:1 — many on one: cheap, but no multicore and one blocking call stalls all. M:N — both benefits, at the price of a complex two-level scheduler.

open as a page

What does it mean to join a thread you started, and what problem does joining solve that simply starting the thread does not?

level: juniorimportance: must knowfreq 60%
basics
~20 s

Joining means one thread blocks until another finishes. Starting a thread only launches it; the starter keeps running and has no idea when the work is done or whether it succeeded. Join gives you completion timing and a safe point to read results.

open as a page

What actually happens when the operating system switches from running one thread to another, and where does the cost of that switch come from?

level: middleimportance: must knowfreq 58%
basics
~20 s

The kernel saves the running thread's registers and program counter, picks another runnable thread, and restores its state; a switch to a different process also swaps page tables. The direct cost is small. The larger, indirect cost is cold caches, branch predictors and address-translation entries when the new thread starts running.

open as a page

You have one coordinator thread that must not proceed until N independent worker tasks have each finished. Describe how a one-shot countdown latch solves this, and what happens to a thread that waits on a latch whose count has already reached zero.

level: juniorimportance: must knowfreq 60%
basics
~20 s

A latch is created with the count N. Each worker decrements it once when done; the coordinator blocks in await until the count reaches zero, then continues. The count never resets, so any wait after zero returns immediately instead of blocking.

open as a page

A consumer thread must wait until a shared queue becomes non-empty before taking an item. Explain the monitor pattern — a mutex paired with a condition variable — and why it is preferred to a loop that sleeps briefly and re-checks the queue.

level: juniorimportance: must knowfreq 58%
basics
~20 s

A monitor is a lock protecting shared state plus a condition variable to wait on. The consumer locks, and while the queue is empty calls wait, which atomically releases the lock and sleeps. A producer adds an item under the lock and signals. Polling wastes CPU and adds latency; waiting costs nothing until woken.

open as a page

What does a mutual-exclusion lock (a mutex) actually guarantee to the code that uses it, and what does it explicitly not guarantee?

level: juniorimportance: must knowfreq 78%
basics
~20 s

At most one thread holds a given mutex, so critical sections guarded by that same lock never overlap, and a holder's writes become visible to the next holder. It promises nothing about acquisition order, fairness, deadlock freedom, or data guarded by another lock.

open as a page

What is a readers-writer lock, how do its shared and exclusive modes interact, and what must be true of a workload for it to beat an ordinary mutex?

level: juniorimportance: must knowfreq 62%
basics
~20 s

It has two modes: many threads may hold it in shared (read) mode at once, but exclusive (write) mode admits one holder and excludes all readers. It only beats a plain mutex when reads greatly outnumber writes and critical sections are long enough to repay its higher bookkeeping cost.

open as a page

What is a semaphore in concurrent programming, and what is the difference between a counting semaphore and a binary semaphore?

level: juniorimportance: must knowfreq 70%
basics
~20 s

A semaphore is a counter of permits with two atomic operations: acquire, which takes a permit and blocks while none are free, and release, which returns one. A counting semaphore starts with N permits; a binary semaphore holds at most one.

open as a page

Two threads each run the statement `counter = counter + 1` one thousand times on a shared variable, with no synchronization. The final value is often less than 2000. Explain why, using what the hardware actually executes.

level: juniorimportance: must knowfreq 72%
basics
~20 s

That one statement is three machine steps: read the value, add one, write it back. Two threads can read the same old value, both add one to it, and both write the same new value — so two increments produce one. Updates are lost whenever the steps interleave.

open as a page

What is a deadlock, and which four conditions must all hold at the same time for one to be possible?

level: juniorimportance: must knowfreq 72%
basics
~10 s

Deadlock is a set of threads permanently blocked, each waiting for a resource another one in the set holds. It requires four conditions at once: mutual exclusion, hold-and-wait, no preemption, circular wait.

open as a page

Interviewers often distinguish a 'data race' from a 'race condition'. Define each precisely, and show that neither one implies the other.

level: middleimportance: must knowfreq 62%
basics
~20 s

A data race is a memory-model property: two threads access the same location concurrently, at least one writes, with no ordering between them. A race condition is a correctness property: the result depends on timing. You can have a race condition with zero data races (all accesses properly synchronized, but the logic assumes state cannot change between steps) and a data race that never produces a wrong-looking answer.

open as a page

Two threads transfer money between accounts, each locking the source account and then the destination. Explain why this can hang forever, how a global lock ordering fixes it, and what you do when the objects being locked have no natural order.

level: middleimportance: must knowfreq 65%
basics
~20 s

Transfer(A,B) and transfer(B,A) take the two locks in opposite orders and can each hold one while waiting for the other. Fix: define one total order over all lockable objects, such as a unique id, and always acquire in that order.

open as a page

What is livelock, and how does it differ from deadlock? Describe the runtime signature of each.

level: middleimportance: must knowfreq 62%
basics
~20 s

Both are liveness failures: no useful work completes. In deadlock the threads are blocked forever waiting on each other, so their states are frozen. In livelock the threads stay runnable and keep changing state (retry, back off, yield) but the pattern repeats and nobody finishes.

open as a page

Two threads each run the statement `count = count + 1` a thousand times on the same shared variable, and the final total is less than two thousand. Explain why, and what it means for an operation to be an atomic read-modify-write.

level: juniorimportance: must knowfreq 78%
basics
~20 s

The statement is three steps: read, add one, write back. Two threads can read the same old value and both write the same new value, so one increment is lost. An atomic read-modify-write performs all three steps as one indivisible hardware operation that no other thread can interleave with.

open as a page

A worker thread spins in a loop reading an ordinary boolean 'stop' variable while another thread sets it to true and then exits. Sometimes the worker never leaves the loop. Explain how that is possible even though the write definitely executed.

level: juniorimportance: must knowfreq 58%
basics
~20 s

Nothing orders the write against the read, so the reader has no obligation to observe it. The compiler may load the variable once into a register and loop on that copy, and the write may sit in the writer's store buffer. Publish the flag through a synchronization edge.

open as a page

In a lock-free algorithm built on compare-and-swap, a thread reads a shared pointer whose value is A, does some work, and its later compare-and-swap from A succeeds — yet the structure ends up corrupted. Explain what went wrong and why a successful compare-and-swap was not enough.

level: middleimportance: must knowfreq 45%
basics
~20 s

That is the ABA problem. Between the read and the compare-and-swap, other threads changed the value to B and back to A. Compare-and-swap only checks that the word is equal now, not that nothing happened meanwhile, so anything the thread inferred from its first read may be stale.

open as a page

Describe how a compare-and-swap instruction works and how you build an arbitrary atomic update on top of it with a retry loop. Why can the loop iterate more than once, and what happens to a thread that keeps losing?

level: middleimportance: must knowfreq 62%
basics
~20 s

Compare-and-swap atomically writes a new value only if the location still equals the value you expected, reporting success or failure. You read, compute a new value, attempt the swap, and loop on failure with a fresh read. A loop iterates when another thread updated the location first; a persistently unlucky thread can starve, though the system as a whole always progresses.

open as a page

Two threads each increment their own private counter, but the two counters are adjacent fields of the same object. Measured throughput is worse than one thread doing both increments, and it gets worse as you add cores. Explain what the hardware is doing and how you would confirm and fix it.

level: middleimportance: must knowfreq 58%
basics
~20 s

False sharing. Coherence tracks whole cache lines, so both counters live in one line; each write must take exclusive ownership and invalidates the other core's copy, so the line ping-pongs between caches. Confirm with coherence-miss counters or by separating the fields; fix by padding or aligning them onto different lines, or by accumulating per thread.

open as a page

What is a coroutine, and what actually happens when one suspends, compared with an operating-system thread that blocks waiting for I/O?

level: juniorimportance: must knowfreq 58%
basics
~20 s

A coroutine is a function that can pause partway through and resume later. Suspending saves its state, hands control back to a scheduler, and frees the underlying thread for other work. A blocked thread keeps its whole stack and OS slot while doing nothing.

open as a page

What is an event loop, and what does run-to-completion mean for the callbacks it dispatches?

level: juniorimportance: must knowfreq 60%
basics
~20 s

An event loop is a single thread cycling forever: wait for ready events, take the next task from a queue, run its handler to completion, repeat. No handler is ever interrupted mid-way by another handler, so loop-owned state needs no locks — but a slow handler delays everything behind it.

open as a page

In asynchronous programming, what is the distinction between a future and a promise, and why do many libraries hand out two separate objects for a single asynchronous result?

level: juniorimportance: must knowfreq 62%
basics
~20 s

A future is the read side of a result that is not ready yet: you await it or attach a continuation. A promise is the write side: the producer completes it once, with a value or an error. Splitting them stops consumers from completing results.

open as a page

When you build a pipeline from steps that each return a future, what is the difference between transforming a future's value with a plain mapping function and chaining a step that itself returns a future — and what breaks if you confuse the two?

level: middleimportance: must knowfreq 56%
basics
~20 s

Mapping applies a synchronous function to the value. Chaining applies a function that returns another future and flattens it, so the result completes when the inner work finishes. Mapping with an async function yields a future of a future: the outer completes early, before the real work is done.

open as a page

How do failures travel through a chain of asynchronous steps built from futures, and why does wrapping the call in a try/catch at the call site usually fail to catch them?

level: middleimportance: must knowfreq 52%
basics
~20 s

A future completes with either a value or an error, and an error short-circuits the downstream transforms until a handler that accepts errors is reached. A try/catch at the call site only sees synchronous failures, because the function returns a pending handle long before the failure exists.

open as a page

Explain the difference between data parallelism and task parallelism, give a concrete example of each, and say what determines how far each one can scale.

level: juniorimportance: must knowfreq 56%
basics
~20 s

Data parallelism runs the same operation over different slices of one data set — its scaling limit is how finely you can split the data. Task parallelism runs different operations concurrently — its scaling limit is the number of independent tasks and their dependency graph. Resizing a million images is data parallel; fetching a user profile and their orders at once is task parallel.

open as a page

Describe the fork-join model of parallel computation: how does a unit of work split itself, and what does the 'join' step guarantee to the code that runs after it?

level: juniorimportance: must knowfreq 50%
basics
~20 s

A task checks whether its input is small enough to do directly. If not, it splits the input into independent pieces, forks them so they can run in parallel, then joins - waits for each piece to finish - and combines their results. Join gives completion and result visibility.

open as a page

Explain the map, shuffle (regroup), and reduce phases of the map-reduce processing model: what does each phase do to the data, and why is the middle phase needed at all?

level: juniorimportance: must knowfreq 50%
basics
~20 s

Map transforms each input record independently into key-value pairs. Shuffle regroups those pairs so that all values for the same key land together on one reducer. Reduce folds each key's group into a result. Without the regroup step a reducer would only see part of each key.

open as a page

Explain pipeline parallelism as a way to organize concurrent work: what a stage is, how items move between stages, and what determines how many items the arrangement finishes per second once it runs steadily.

level: juniorimportance: must knowfreq 55%
basics
~20 s

Split a repeated job into ordered steps called stages, each with its own worker and a queue in front of it. Different items sit in different stages at the same time, so all workers run at once. Steady-state throughput is one item per slowest stage's time.

open as a page

In a recursive divide-and-conquer parallel algorithm, why do implementations stop splitting once a subproblem is below some size and run the remainder sequentially, and how would you choose that threshold?

level: middleimportance: must knowfreq 45%
basics
~20 s

Each split costs bookkeeping - creating, queueing and scheduling a task. Below some size that overhead exceeds the useful work, so the recursion would slow things down. Pick the threshold by measuring: choose the smallest size where parallel still beats sequential, comfortably above the break-even point.

open as a page

A service runs its work on a fixed set of worker threads fed by a task queue. What happens when every worker is already busy and new tasks keep arriving, and how does that show up to the callers submitting work?

level: juniorimportance: must knowfreq 58%
basics
~20 s

New tasks wait in the queue instead of running. Throughput stays flat at what the workers can serve, so latency climbs as the backlog grows. An unbounded queue eats memory; a bounded one eventually refuses work or blocks the submitter.

open as a page

When an application is stopping, its worker pool may still hold queued tasks and tasks that are mid-execution. Describe the difference between an orderly shutdown and an immediate one, and what each does with those two categories of work.

level: juniorimportance: must knowfreq 56%
basics
~20 s

Orderly shutdown stops accepting new submissions but drains the queue and lets running tasks finish. Immediate shutdown also refuses new work, discards the queue - returning the undone tasks - and signals running tasks to stop. Both requests return at once; termination happens later.

open as a page

You ask a scheduler to run a piece of work once, 100 milliseconds from now. Explain what that request actually guarantees, how a scheduler typically decides what to run next, and why the work might start noticeably later than 100 ms.

level: juniorimportance: must knowfreq 50%
basics
~20 s

A delay is a lower bound, not an appointment: the task will not start before 100 ms, but it may start much later. The scheduler keeps pending tasks ordered by due time and can only run one when a worker is free and the clock has passed it.

open as a page

A service processes CPU-heavy tasks in a worker pool on an 8-core machine. A colleague proposes raising the pool from 8 workers to 200 to make it faster. Why does throughput usually not improve, and how can it get worse?

level: juniorimportance: must knowfreq 60%
basics
~20 s

Only 8 tasks can actually compute at once, so throughput is already capped by the cores. Extra workers add context switches, cache pollution, memory for stacks and more lock contention. Throughput flattens then dips, and per-task latency rises because more work is in flight.

open as a page

A task running on a bounded worker pool submits a second task to that same pool and then blocks waiting for the second task's result. Explain why this arrangement can deadlock, and what determines whether it actually will.

level: middleimportance: must knowfreq 54%
basics
~20 s

The waiting parent still occupies a worker. If every worker is a blocked parent, no worker is left to run the queued children, so parents wait on children that can never start. It is a resource deadlock where the scarce resource is the worker thread.

open as a page

In a concurrent system, what does it actually mean to cancel a running task, and why is cancelling a task different from simply ignoring the result it eventually produces?

level: juniorimportance: must knowfreq 55%
basics
~20 s

Cancelling means asking a running task to stop early and release what it holds; the task must notice the request and wind down. Ignoring its result stops nothing: it keeps burning CPU, connections and memory, and its side effects still happen.

open as a page

A background task is started fire-and-forget — nobody keeps its handle or waits for it — and it throws. What typically happens to that error, and why is it dangerous?

level: juniorimportance: must knowfreq 50%
basics
~20 s

With no owner waiting, the error has nowhere to propagate: it ends that task and lands in a default handler, an unread log line, or a result object nobody inspects. The system keeps reporting healthy while the work silently is not being done.

open as a page

A developer starts a background task by spawning it and immediately returning, keeping no handle to it. What can go wrong with such fire-and-forget tasks?

level: juniorimportance: must knowfreq 58%
basics
~20 s

Nobody owns it. Failures vanish silently, nobody waits for it, it can outlive the data and resources it borrowed, it cannot be cancelled or given a deadline, and shutdown can kill it mid-work. The leak stays invisible.

open as a page

What is a cancellation checkpoint, and how would you make a 30-second CPU-bound computation loop cancellable? What determines how quickly cancellation actually takes effect?

level: middleimportance: must knowfreq 52%
basics
~20 s

A checkpoint is a point where the task tests the cancellation signal and abandons the work if it is set. Blocking and awaiting operations usually provide them implicitly; a pure compute loop has none, so you poll the signal every N iterations. Cancellation latency is roughly the time between checkpoints plus cleanup time.

open as a page

Why do modern concurrency runtimes make cancellation cooperative — the task must observe a signal — instead of forcibly terminating it from outside, and where does a thread-level interruption flag fit into that model?

level: middleimportance: must knowfreq 60%
basics
~20 s

Forced termination stops a task at an arbitrary instruction, so invariants are half-updated, locks and buffers are left in unknown states, and no cleanup runs. Cooperative cancellation stops only at safe points. A thread interruption flag is the same idea at thread level: a bit that blocking operations honour by aborting early.

open as a page

Describe the actor model of concurrency: what an actor consists of, and why processing one message at a time removes the need for locks around an actor's state.

level: juniorimportance: must knowfreq 50%
basics
~20 s

An actor is an isolated unit with private state, a mailbox, and behaviour. Actors never share memory; they only send each other asynchronous messages. Each actor processes its mailbox strictly one message at a time, so its state is never touched concurrently and needs no lock.

open as a page

What is the CSP (Communicating Sequential Processes) model of concurrency, and how does coordinating tasks by passing values over channels differ from coordinating them with shared mutable state and locks?

level: juniorimportance: must knowfreq 50%
basics
~20 s

CSP models a program as independent sequential processes that share no memory and interact only by sending and receiving values on channels. The communication is itself the synchronization, so there is no shared mutable state to lock.

open as a page

When concurrent tasks exchange data as messages, what properties must the message type have for any number of receivers to read it safely without coordinating, and what does immutable have to mean for a value that contains other objects inside it?

level: juniorimportance: must knowfreq 55%
basics
~20 s

The message must be fully built before it is sent and never change afterwards, all the way down: nested objects, arrays and collections must be immutable too, and the sender must keep no reference it can mutate. Then every reader sees identical content regardless of timing.

open as a page

Describe the producer-consumer pattern built around a bounded buffer: which threads block, under what conditions, and what problem the arrangement solves that a direct call would not.

level: juniorimportance: must knowfreq 68%
basics
~20 s

Producers put work items into a shared fixed-size buffer; consumers take them out. A producer blocks when the buffer is full, a consumer blocks when it is empty. This decouples the two sides in time and rate while the fixed capacity stops a fast producer from exhausting memory.

open as a page

What message ordering and delivery guarantees do actor systems typically provide, what do they explicitly not provide, and how does that change the way you write message handlers?

level: middleimportance: must knowfreq 42%
basics
~20 s

Typically at-most-once delivery, with FIFO order preserved only per sender-receiver pair. There is no global ordering, no causal ordering through intermediaries, and no guaranteed delivery. So handlers must tolerate lost, delayed and interleaved messages, and be idempotent if you add retries.

open as a page

A colleague tests asynchronous code by starting the work, sleeping for 100 milliseconds, and then asserting the result. Why is that approach problematic, and what should the test wait on instead?

level: juniorimportance: must knowfreq 70%
basics
~20 s

A fixed sleep is a guess about duration. Too short and the test fails on a loaded machine; too long and the suite crawls. Wait on a real completion signal instead — a future, a latch, a callback, or a quiescence check — with a generous timeout.

open as a page

What is a data race, and what does a dynamic race detector actually observe at runtime in order to decide that two memory accesses race?

level: juniorimportance: must knowfreq 58%
basics
~20 s

A data race is two threads accessing the same memory location, at least one of them writing, with no synchronization ordering the accesses. A dynamic detector instruments every load, store and synchronization event at runtime and checks whether each pair of conflicting accesses is ordered.

open as a page

What is a virtual (fake) clock in a test suite, and which kinds of behaviour become testable when application code reads time through an injected clock instead of calling the system clock directly?

level: middleimportance: must knowfreq 58%
basics
~20 s

A virtual clock is a time source the test controls: it only advances when the test says so. Injecting it lets you test timeouts, retry backoff, cache expiry, rate limiting, and scheduled jobs instantly and deterministically, with no real waiting.

open as a page

A running service stops serving requests while its processor usage sits near zero. How do you use thread dumps — snapshots of every thread's stack and state — to work out what it is stuck on?

level: middleimportance: must knowfreq 62%
basics
~20 s

Take several dumps a few seconds apart and compare. Near-zero processor use means nobody is running, so look for threads blocked on a lock (and who owns it), waiting on a condition or a remote response, and for whole worker pools stuck in the same stack — that shared frame is the culprit.

open as a page

Simply running a multi-threaded test in a loop usually finds nothing. How would you design a stress harness that actually surfaces an interleaving bug?

level: middleimportance: must knowfreq 48%
basics
~20 s

Shrink the code under test so the bad window is a large fraction of it, start all threads from a barrier so they collide instead of running sequentially, perturb timing with randomized delays and varied thread counts, check a real invariant rather than a crash, and record the seed and observed state so a failure is reproducible.

open as a page