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 courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.