import asyncio async def main(): tasks = [] async def task_A(lock): print("Task A: acquiring lock;", lock) async with lock: print("Task A: acquired;", lock) await asyncio.sleep(1) print("Task A: released;", lock) task_B = tasks[1] task_B.cancel() # In release() B's waiting future is resolved so # the task B should acquire lock next. # Assume it gets cancelled in the same loop iteration. # Task's B cancel() method will try to cancel waiting future # but it is already resolved so the task is flagged with _must_cancel. # On next loop iteration task B's acquire() will be cancelled thus # not calling Lock.release() and not waiking up next lock waiter. async def task_N(lock, name): print("Task {}: Acquire lock;".format(name), lock) try: await lock.acquire() except asyncio.CancelledError: print("Task {}: cancelled;".format(name), lock) raise try: print("Task {}: acquired;".format(name), lock) finally: print("Task {}: released;".format(name), lock) lock.release() lock = asyncio.Lock() tasks = [ asyncio.ensure_future(task_A(lock)), asyncio.ensure_future(task_N(lock, 'B')), asyncio.ensure_future(task_N(lock, 'C')), ] await asyncio.gather(*tasks, return_exceptions=True) if __name__ == '__main__': loop = asyncio.get_event_loop() loop.run_until_complete(main())