@@ -210,6 +210,49 @@ def intersect(first, second):
210210
211211 self .assertEqual (target , expected )
212212
213+ def test_intersection_update_suspended_lock (self ):
214+ """Test an update while a later operand's lock is held."""
215+ NUM_ITERS = 200
216+ BLOCK_SIZE = self .SET_SIZE * 1_000
217+ HOLD_WORK = 10_000
218+
219+ initial = set (range (BLOCK_SIZE ))
220+ blocked_operand = set (initial )
221+ evens = set (range (0 , BLOCK_SIZE , 2 ))
222+ threes = set (range (0 , BLOCK_SIZE , 3 ))
223+ expected = set (range (0 , BLOCK_SIZE , 6 ))
224+
225+ class SlowEmpty :
226+ def __iter__ (self ):
227+ for _ in range (HOLD_WORK ):
228+ pass
229+ return iter (())
230+
231+ # Repeat because the lock suspension depends on thread scheduling.
232+ for _ in range (NUM_ITERS ):
233+ target = set (initial )
234+
235+ def hold_operand ():
236+ blocked_operand .intersection (SlowEmpty ())
237+
238+ def first_update ():
239+ target .intersection_update (evens , blocked_operand )
240+
241+ def second_update ():
242+ target .intersection_update (threes )
243+
244+ threads = [
245+ Thread (target = hold_operand ),
246+ Thread (target = first_update ),
247+ Thread (target = second_update ),
248+ ]
249+ for thread in threads :
250+ thread .start ()
251+ for thread in threads :
252+ thread .join ()
253+
254+ self .assertEqual (target , expected )
255+
213256 def test_iand_concurrent (self ):
214257 """Test concurrent &= operations on one shared set."""
215258 NUM_ITERS = 10
0 commit comments