Sorting Out the Terms
People throw around "deadlock" when they mean several different concurrency problems. In async .NET, the distinctions matter because the fix for each is radically different.
Deadlock
Two or more tasks wait indefinitely for each other to release a lock or complete a continuation. Classic example: Task A awaits Task B, and Task B awaits Task A, with both holding locks.
Livelock
Tasks are active and responding, but make no progress. They keep retrying an operation, yielding to each other in a loop. Think of two async methods that back off and retry on conflict forever.
Starvation
A task is ready to run but never gets scheduled because higher-priority work monopolizes the thread pool. In async code, this often looks like a low-priority background task that never fires because the pool is saturated with CPU-bound work.
Profiling tells you which one you have. Deadlock shows threads in wait states. Livelock shows high CPU with no I/O completion. Starvation shows tasks queued but never dequeued.