How to check possibility of deadlock in c code
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
A deadlock occurs when two or more threads are blocked forever, each waiting for a lock held by the other. In C#, deadlocks commonly happen with lock statements, Monitor, Mutex, SemaphoreSlim, and async/await patterns. Detecting and preventing deadlocks requires understanding the four conditions that must all be present: mutual exclusion, hold and wait, no preemption, and circular wait.
Classic Deadlock Example
Detection Method 1: Consistent Lock Ordering
The most effective prevention is acquiring locks in the same global order everywhere:
To enforce this programmatically, assign a numeric order to each lock:
Detection Method 2: Timeouts
Use Monitor.TryEnter with a timeout to detect potential deadlocks at runtime:
Detection Method 3: async/await Deadlocks
The most common C# deadlock in modern code involves async/await with .Result or .Wait():
Fix: Use async all the way down, or use ConfigureAwait(false):
Detection Method 4: Visual Studio Debugger
When a deadlock occurs during debugging:
- Debug → Break All (Ctrl+Alt+Break)
- Debug → Windows → Threads — shows all threads and their states
- Debug → Windows → Parallel Stacks — visualizes thread call stacks
- Look for threads in "Waiting" state with stack traces showing
Monitor.EnterorWaitOne
Detection Method 5: Static Analysis
Use tools that detect potential deadlocks at compile time:
Detection Method 6: Resource Wait Graph
Build a wait-for graph at runtime and check for cycles:
Common Pitfalls
- Blocking on async code: Calling
.Result,.Wait(), or.GetAwaiter().GetResult()on async methods is the #1 cause of deadlocks in modern C#. Useawaitinstead. - Locking on
thisortypeof:lock(this)orlock(typeof(MyClass))allows external code to lock on the same object, creating unexpected contention. Always lock on privatereadonlyobjects. - Nested locks: Acquiring multiple locks in different orders across methods is hard to detect through code review. Use the OrderedLock pattern or reduce the number of locks.
- Thread pool starvation: Not a classic deadlock, but blocking all thread pool threads (e.g., with
.ResultinsideTask.Run) prevents other work from completing, creating a deadlock-like hang. - Debugging intermittent deadlocks: Deadlocks may only reproduce under specific timing. Use stress testing and tools like CHESS or Coyote for systematic exploration of thread interleavings.
Summary
- Prevent deadlocks by acquiring locks in a consistent global order
- Use
Monitor.TryEnterwith timeouts to detect deadlocks at runtime instead of hanging forever - Never call
.Resultor.Wait()on async methods — useawaitall the way - Use Visual Studio's Parallel Stacks and Threads windows to diagnose deadlocks during debugging
- Lock only on private
readonly objectfields, never onthis,typeof, or string literals
Related reading
- How to combine python asyncio with threads?
- How to configure a fine tuned thread pool for futures?
- How to consume WinRT IAsyncOperation object in native c environment
- How to convert a function in a third party library to be async?
- How to check programmatically if a type is a struct or a class?
- How to check that Request.QueryString has a specific value or not in ASP.NET?
- How to convert a Future into a Stream?
- How to convert a list of generic tasks of different types that are stored in a ListTask, to a TaskListobject?

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseInterview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.