Limited Offer
60% OFF on all plans!

Concurrency & Delay in C#

Pause execution with Task.Delay, run tasks with Task.Run, coordinate with Task.WhenAll / Task.WhenAny, use CancellationToken, and prevent race conditions with lock and Interlocked.

Waiting & Async Execution

1. Wait for N Milliseconds

Use `await Task.Delay(ms)` to pause without blocking the thread.

2. Run a Function Asynchronously

`Task.Run()` offloads CPU-bound work to a thread-pool thread.

Coordinating Async Operations

1. Wait for Multiple Async Tasks (Task.WhenAll)

`Task.WhenAll` runs tasks concurrently and waits until all finish.

2. Wait for At Least One Task (Task.WhenAny)

`Task.WhenAny` completes as soon as the first task finishes.

Task Chaining

1. ContinueWith() — Chain After Completion

`ContinueWith` runs a callback when the preceding task finishes.

2. Handling Exceptions with ContinueWith()

When a task faults, `ContinueWith` still runs. Access the exception via `t.Exception` — but you must observe it, otherwise the exception is silently swallowed. Use `TaskContinuationOptions` to run callbacks only on specific outcomes.

3. Handling Errors in Async Code

Use try/catch inside async methods — exceptions propagate naturally.

4. finally in Async Code

`finally` blocks work as expected in async methods.

5. ContinueWith vs async/await

`async/await` is the modern preferred style — cleaner than ContinueWith chains.

Passing Data Between Async & Sync Code

1. Passing Data from an Async Method

Return `Task<T>` from async methods and `await` to extract the value.

Timers & Intervals

1. Perform Operation After Delay

`Task.Delay` + `await` is the idiomatic async delay.

2. Perform Operation at Every Interval

`PeriodicTimer` (.NET 6+) is the modern tick-based interval — no callback required.

Measuring Time Intervals

1. Calculating Time Interval

`Stopwatch` from `System.Diagnostics` measures elapsed time with high precision.

Parallel Execution

1. Running Tasks in Parallel with Task.Run

Fire multiple `Task.Run` calls without awaiting immediately, then collect with `Task.WhenAll`.

2. Raw Thread Creation

Create a low-level OS thread using `new Thread(...)`. Use `Start()` to launch and `Join()` to wait for completion.

3. Parallel.For and Parallel.ForEach

`Parallel.For` and `Parallel.ForEach` parallelise loops across all CPU cores.

Thread Safety & Synchronization

1. Race Condition Problem

Two threads modifying shared state simultaneously produces incorrect results.

2. Fix with Interlocked

`Interlocked.Increment` performs atomic increment — no lock needed for simple counters.

3. Fix with lock

`lock(obj)` ensures only one thread executes the protected block at a time.

4. Deadlock — Problem and Prevention

A deadlock occurs when two threads each wait for a lock held by the other — they block forever. Fix by always acquiring locks in a consistent order.

5. SemaphoreSlim — Limit Concurrency

`SemaphoreSlim` limits how many tasks can execute a section concurrently.