@@ -12,7 +12,7 @@ def test_repr_clear(self):
1212 """Test repr() of a set while another thread is calling clear()"""
1313 NUM_ITERS = 10
1414 NUM_REPR_THREADS = 10
15- barrier = Barrier (NUM_REPR_THREADS + 1 )
15+ barrier = Barrier (NUM_REPR_THREADS + 1 , timeout = 2 )
1616 s = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 }
1717
1818 def clear_set ():
@@ -38,12 +38,12 @@ def repr_set():
3838
3939 def test_contains_mutate (self ):
4040 """Test set contains operation combined with mutation."""
41- barrier = Barrier (2 )
41+ barrier = Barrier (2 , timeout = 2 )
4242 s = set ()
4343 done = False
4444
45- NUM_ITEMS = 2_000
46- NUM_LOOPS = 20
45+ NUM_ITEMS = 200
46+ NUM_LOOPS = 200
4747
4848 def read_set ():
4949 barrier .wait ()
@@ -72,29 +72,82 @@ def mutate_set():
7272 t .join ()
7373
7474 def test_contains_frozenset (self ):
75- barrier = Barrier (3 )
75+ barrier = Barrier (3 , timeout = 2 )
7676 done = False
7777
78- NUM_ITEMS = 2_000
79- NUM_LOOPS = 20
78+ NUM_LOOPS = 1_000
8079
81- s = frozenset ()
82- def make_set ():
83- nonlocal s
80+ # This mutates the key used for contains test, not the container
81+ # itself. This works because frozenset allows the key to be a set().
82+ s = set ()
83+
84+ def mutate_set ():
8485 barrier .wait ()
8586 while not done :
86- s = frozenset (range (NUM_ITEMS ))
87+ s .add (0 )
88+ s .add (1 )
89+ s .clear ()
8790
8891 def read_set ():
8992 nonlocal done
9093 barrier .wait ()
94+ container = frozenset ([frozenset ([0 ])])
95+ self .assertTrue (set ([0 ]) in container )
9196 for _ in range (NUM_LOOPS ):
92- for i in range (NUM_ITEMS ):
93- item = i >> 1
94- result = item in s
97+ # Will return True when {0} is the key and False otherwise
98+ result = s in container
9599 done = True
96100
97- threads = [Thread (target = read_set ), Thread (target = read_set ), Thread (target = make_set )]
101+ threads = [
102+ Thread (target = read_set ),
103+ Thread (target = read_set ),
104+ Thread (target = mutate_set ),
105+ ]
106+ for t in threads :
107+ t .start ()
108+ for t in threads :
109+ t .join ()
110+
111+ def test_contains_hash_mutate (self ):
112+ """Test set contains operation with mutating hash method."""
113+ barrier = Barrier (2 , timeout = 2 )
114+
115+ NUM_ITEMS = 20 # should be larger than PySet_MINSIZE
116+ NUM_LOOPS = 1_000
117+
118+ s = set (range (NUM_ITEMS ))
119+
120+ class Key :
121+ def __init__ (self ):
122+ self .count = 0
123+ self .value = 0
124+
125+ def __hash__ (self ):
126+ self .count += 1
127+ # This intends to trigger the SET_LOOKKEY_CHANGED case
128+ # of set_lookkey_threadsafe() since calling clear()
129+ # will cause the 'table' pointer to change.
130+ if self .count % 2 == 0 :
131+ s .clear ()
132+ else :
133+ s .update (range (NUM_ITEMS ))
134+ return hash (self .value )
135+
136+ def __eq__ (self , other ):
137+ return self .value == other
138+
139+ key = Key ()
140+ self .assertTrue (key in s )
141+ self .assertFalse (key in s )
142+ self .assertTrue (key in s )
143+ self .assertFalse (key in s )
144+
145+ def read_set ():
146+ barrier .wait ()
147+ for i in range (NUM_LOOPS ):
148+ result = key in s
149+
150+ threads = [Thread (target = read_set ), Thread (target = read_set )]
98151 for t in threads :
99152 t .start ()
100153 for t in threads :
0 commit comments