@@ -174,3 +174,81 @@ async def write(lock):
174174 lock = RWLock (fast = True )
175175 await asyncio .gather (write_wait (lock ), write (lock ))
176176 assert seq == ['READ' , 'START2' , 'FIN2' , 'START1' , 'FIN1' ]
177+
178+
179+ @pytest .mark .asyncio
180+ async def test_cancelled_reader_waiters () -> None :
181+ rwlock = RWLock ()
182+ rl = rwlock .reader
183+ wl = rwlock .writer
184+ acquired = False
185+
186+ # Scenario:
187+ # - task A (this) acquires write lock
188+ # - tasks B, C wait for read lock
189+ #
190+ # C gets cancelled while waiting for A to release the lock
191+ # B should proceed without deadlock
192+
193+ async def read_task () -> None :
194+ nonlocal acquired
195+ async with rl :
196+ acquired = True
197+
198+ async with wl :
199+ assert wl .locked
200+ # Create reader tasks that will wait
201+ task_b = ensure_future (read_task ())
202+ task_c = ensure_future (read_task ())
203+ await asyncio .sleep (0.1 )
204+ # Cancel one of the waiting readers
205+ task_c .cancel ()
206+ await asyncio .sleep (0.1 )
207+
208+ with pytest .raises (asyncio .CancelledError ):
209+ await task_c
210+
211+ # Task B should complete without deadlock
212+ await asyncio .wait_for (task_b , timeout = 1.0 )
213+ assert acquired
214+ assert not rl .locked
215+ assert not wl .locked
216+
217+
218+ @pytest .mark .asyncio
219+ async def test_cancelled_writer_waiters () -> None :
220+ rwlock = RWLock ()
221+ rl = rwlock .reader
222+ wl = rwlock .writer
223+ acquired = False
224+
225+ # Scenario:
226+ # - task A (this) acquires read lock
227+ # - tasks B, C wait for write lock
228+ #
229+ # C gets cancelled while waiting for A to release the lock
230+ # B should proceed without deadlock
231+
232+ async def write_task () -> None :
233+ nonlocal acquired
234+ async with wl :
235+ acquired = True
236+
237+ async with rl :
238+ assert rl .locked
239+ # Create writer tasks that will wait
240+ task_b = ensure_future (write_task ())
241+ task_c = ensure_future (write_task ())
242+ await asyncio .sleep (0.1 )
243+ # Cancel one waiting writer
244+ task_c .cancel ()
245+ await asyncio .sleep (0.1 )
246+
247+ with pytest .raises (asyncio .CancelledError ):
248+ await task_c
249+
250+ # Task B should complete without deadlock
251+ await asyncio .wait_for (task_b , timeout = 1.0 )
252+ assert acquired
253+ assert not rl .locked
254+ assert not wl .locked
0 commit comments