@@ -1332,6 +1332,23 @@ def _on_queue_feeder_error(e, obj):
13321332 self .assertTrue (not_serializable_obj .reduce_was_called )
13331333 self .assertTrue (not_serializable_obj .on_queue_feeder_error_was_called )
13341334
1335+ def test_closed_queue_empty_exceptions (self ):
1336+ # Assert that checking the emptiness of an unused closed queue
1337+ # does not raise an OSError. The rationale is that q.close() is
1338+ # a no-op upon construction and becomes effective once the queue
1339+ # has been used (e.g., by calling q.put()).
1340+ for q in multiprocessing .Queue (), multiprocessing .JoinableQueue ():
1341+ q .close () # this is a no-op since the feeder thread is None
1342+ q .join_thread () # this is also a no-op
1343+ self .assertTrue (q .empty ())
1344+
1345+ for q in multiprocessing .Queue (), multiprocessing .JoinableQueue ():
1346+ q .put ('foo' ) # make sure that the queue is 'used'
1347+ q .close () # close the feeder thread
1348+ q .join_thread () # make sure to join the feeder thread
1349+ with self .assertRaisesRegex (OSError , 'is closed' ):
1350+ q .empty ()
1351+
13351352 def test_closed_queue_put_get_exceptions (self ):
13361353 for q in multiprocessing .Queue (), multiprocessing .JoinableQueue ():
13371354 q .close ()
@@ -5815,6 +5832,15 @@ def _test_empty(cls, queue, child_can_start, parent_can_continue):
58155832 finally :
58165833 parent_can_continue .set ()
58175834
5835+ def test_empty_exceptions (self ):
5836+ # Assert that checking emptiness of a closed queue raises
5837+ # an OSError, independently of whether the queue was used
5838+ # or not. This differs from Queue and JoinableQueue.
5839+ q = multiprocessing .SimpleQueue ()
5840+ q .close () # close the pipe
5841+ with self .assertRaisesRegex (OSError , 'is closed' ):
5842+ q .empty ()
5843+
58185844 def test_empty (self ):
58195845 queue = multiprocessing .SimpleQueue ()
58205846 child_can_start = multiprocessing .Event ()
0 commit comments