Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

C# & .NET (C# 14, .NET 10 LTS) Module 16

Threads, parallelism and synchronisation interview questions

Interview questions on threads, parallelism and synchronisation: warm-ups, then what each harder question tests and how a good answer starts.

19 questions: 5 warm-ups and 14 with model answers · Levels: Fresher to staff

Warm-up questions

Short questions with short answers, each answered in full.

  1. Fresher

    What is the difference between a foreground and a background thread in .NET?

    Answered in the lesson Threads, the thread pool and async-local state

  2. Fresher

    Why is count++ not thread-safe in C#?

    Answered in the lesson Locks, Interlocked and the .NET memory model

  3. Fresher to mid

    What does a bounded channel do when it is full?

    Answered in the lesson Concurrent collections and channels

  4. Fresher to mid

    What is the difference between limiting concurrency and limiting rate?

    Answered in the lesson Throttling with SemaphoreSlim and rate limiters

  5. Fresher to mid

    When does Parallel.For make a loop slower?

    Answered in the lesson Parallel.For, Parallel.ForEach and PLINQ

Questions with model answers

What each question tests, the first step of a good answer and the follow-ups to expect.

  1. Mid to senior

    A queue worker starts a new Thread for every message it receives. At 2,000 messages a minute its memory keeps rising and messages wait longer and longer. What is going on, and how do you move it to the thread pool without breaking the messages that block?

    What it tests
    The cost of threads against the pool, telling short CPU work from blocking work and I/O, and what changes for errors and shutdown after the move.
    First step
    Find out what a message does: short CPU work, a blocking call or an I/O wait. 2,000 a minute is about 33 a second; if each one blocks for seconds, threads are created faster than they finish, and each holds its own stack.
    Follow-ups

    From the lesson Threads, the thread pool and async-local state

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.

    Opening the model answers with your pass…

    Model answers open with any MySmartCoPilot pass.

    • Pro pass · 1 week₹79$2.99
    • 30 days₹179$5.99
    • 1 year₹1,699$45

    One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

    It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  2. Mid to senior

    Log lines from one user's checkout show another user's request id. The id is kept in a [ThreadStatic] field that is set where each request starts, and the handlers are async. Explain the bug and fix it.

    What it tests
    Thread-local state against async flows, how AsyncLocal values flow into calls and not back, and keeping a request's id out of background work.
    First step
    Notice that an async handler can resume on another pool thread after every await, and that each pool thread runs many requests in turn: a [ThreadStatic] id belongs to a thread, not to a request.
    Follow-ups

    From the lesson Threads, the thread pool and async-local state

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  3. Mid to senior

    A payment service hangs a few times a week: two threads are stuck, and every later request waits behind them. Transfer locks the payer's account, then the payee's. Explain the hang and fix it so that it cannot happen again.

    What it tests
    Recognising a lock-order deadlock, the fix that rules it out for good, detecting the next one with time limits, and the cost of the alternatives.
    First step
    Look for two transfers in opposite directions between the same two accounts: each holds its first lock and waits for the other's. Then list every code path that takes two account locks, and the order in which each one takes them.
    Follow-ups

    From the lesson Locks, Interlocked and the .NET memory model

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  4. Mid to senior

    A teammate fixed a lost-update bug by marking a counter field volatile. The nightly test with eight threads still counts too few. Explain why volatile did not help, and what each correct fix costs.

    What it tests
    What volatile guarantees under the .NET memory model and what it does not, atomic updates with Interlocked, and when a lock is needed instead.
    First step
    Separate ordering from atomicity: volatile makes each read and each write of the field fresh and ordered, but count++ is still a read, an add and a write that another thread can come between.
    Follow-ups

    From the lesson Locks, Interlocked and the .NET memory model

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  5. Mid to senior

    At start-up a service logs that it loaded its pricing settings 8 times, and some requests used other settings than others. The property is written as if (_settings == null) _settings = Load(). Explain it and replace it.

    What it tests
    Check-then-act races in lazy initialisation, Lazy<T> and its modes, when double-checked locking is correct in .NET, and failures during the load.
    First step
    Count the threads that can pass the null test before the first Load returns: every request that arrives while it runs. Each builds its own settings and keeps using the object it built.
    Follow-ups

    From the lesson Locks, Interlocked and the .NET memory model

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  6. Mid to senior

    A currency service caches exchange rates in a ConcurrentDictionary with GetOrAdd(code, LoadRates). During a traffic spike the rates provider starts refusing calls, because it received 40 identical requests in one second. Why, and what do you change?

    What it tests
    Why GetOrAdd's factory can run several times for one key, how to load each key once, what a failed load leaves behind, and keeping side effects out of factories.
    First step
    Note that the factory runs outside the dictionary's locks: every request that misses the key before the first load is stored runs LoadRates. Count the requests that arrive within one load's time.
    Follow-ups

    From the lesson Concurrent collections and channels

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 2 minutes
  7. Mid to senior

    A service writes telemetry events into Channel.CreateUnbounded and a background consumer posts them in batches to a collector. During a two-hour collector outage the process grew by 3 GB and was restarted, losing every queued event. What would you change?

    What it tests
    Back-pressure with bounded channels, choosing a full mode by what the data is worth, sizing the bound, and making the loss visible.
    First step
    Work out the backlog: the producer's rate times the outage. An unbounded channel keeps all of it in memory, so decide how much may wait, and what happens to the rest once that is full.
    Follow-ups

    From the lesson Concurrent collections and channels

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  8. Senior to staff

    A log pipeline of a reader, four parsers and an aggregator, joined by channels, sometimes reports counts that are too low, and nothing is logged. A malformed line was found in the input. Explain how the error disappeared, and how errors should travel through such a pipeline.

    What it tests
    How an error travels between the stages of a channel pipeline, observing faulted tasks, who completes a channel that several stages write to, and stopping the other stages when one fails.
    First step
    Follow the malformed line: the parser that reads it throws and its task faults. Then ask who awaits that task, and how the channel after the parsers gets completed.
    Follow-ups

    From the lesson Concurrent collections and channels

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  9. Mid to senior

    Your service calls a partner API that allows 100 requests a minute for each API key, from 4 instances. You added SemaphoreSlim(10) around the calls and still get 429 Too Many Requests. Why, and what do you build?

    What it tests
    Telling a concurrency limit from a rate limit, limits per instance against a shared budget, and handling a 429 with its Retry-After hint.
    First step
    Work out what the semaphore allows: 10 calls at once of about 200 ms each is about 3,000 calls a minute from one instance. The partner counts starts per minute, which the semaphore never counts.
    Follow-ups

    From the lesson Throttling with SemaphoreSlim and rate limiters

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  10. Mid to senior

    After an outage of a payment provider, the workers of an order service stop processing. A dump shows every worker awaiting SemaphoreSlim.WaitAsync, and the provider has been healthy for an hour. What happened, and how do you make sure it cannot recur unnoticed?

    What it tests
    Places leaked on failure paths, Release in finally, time limits on waits, releases that come once too often, and watching CurrentCount.
    First step
    Look at every path between WaitAsync and Release. A Release that a thrown exception skips leaks one place per failure, and an outage produces many failures in a row.
    Follow-ups

    From the lesson Throttling with SemaphoreSlim and rate limiters

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 2 minutes
  11. Senior to staff

    Design a per-user limit of 10 requests a minute with bursts of up to 3 for a public API, and explain how you would test its edges without waiting minutes in every test.

    What it tests
    Token bucket design per key, partitioned limiters, retry-after answers, testing time through an injected clock, and what a limit means across instances.
    First step
    Pick the algorithm from the requirement: a burst of 3 and an average of 10 a minute is a token bucket of 3 tokens with one token back every 6 s, kept for each user.
    Follow-ups

    From the lesson Throttling with SemaphoreSlim and rate limiters

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  12. Mid to senior

    A developer replaced a for loop over 2,000 orders with Parallel.For, and the endpoint got slower while its processor use doubled. When does this happen, and how do you decide whether to parallelise a loop?

    What it tests
    The fixed cost of a parallel loop against the work per item, measuring before and after, and the parallelism a server already gets from its requests.
    First step
    Estimate the work per order against the cost of handing out iterations, then ask what else the server's processors are doing while this one request runs.
    Follow-ups

    From the lesson Parallel.For, Parallel.ForEach and PLINQ

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  13. Senior to staff

    A CPU-bound batch job runs 6 times faster on 16 cores than on 1, and adding cores barely helps. Explain what limits it, and what you would measure to raise the speed-up.

    What it tests
    Amdahl's law with numbers, the serial part, uneven work and partitioning, and contention for shared state or memory.
    First step
    Fit Amdahl's law to the measurement: work out what share of the job must behave as serial for 16 cores to give only 6 times one core, and what ceiling that share sets however many cores are added.
    Follow-ups

    From the lesson Parallel.For, Parallel.ForEach and PLINQ

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  14. Fresher to mid

    A nightly job collects results with results.Add(x) inside Parallel.ForEach. Its totals are off by a few hundred on some nights, and about once a week it fails with an IndexOutOfRangeException. Explain both and fix them.

    What it tests
    Why List<T> is not safe for concurrent adds, the pattern of a collection per thread, concurrent collections, and testing parallel code.
    First step
    Write down, step by step, what List<T>.Add has to do to store one item, then ask what happens when two threads run those steps on the same list at the same moment, including the moment the list grows.
    Follow-ups

    From the lesson Parallel.For, Parallel.ForEach and PLINQ

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes

All C# & .NET (C# 14, .NET 10 LTS) interview questions · The C# & .NET (C# 14, .NET 10 LTS) track

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.