Start here. This is the direct spoken answer to practice first.
Why this question matters
This scenario appears when developers mix synchronous critical sections and asynchronous workflows. The useful answer focuses on minimizing critical sections and avoiding I/O under synchronization.
Holding synchronization while awaiting is dangerous because the operation pauses while still owning a resource other work may need. With lock, C# does not allow await inside the block, but similar problems can happen with SemaphoreSlim or other coordination. The safe approach is to keep critical sections short and avoid slow I/O while holding them. I would capture or update shared state quickly, release the synchronization, then perform async work outside the critical section.