@@ -167,56 +167,68 @@ public async Task WhenCallersRunConcurrentlyResultIsFromWinner()
167167 winnerCount . Should ( ) . Be ( 1 ) ;
168168 }
169169
170- [ Fact ( Skip = "Unstable" ) ]
170+ [ Fact ]
171171 public async Task WhenCallersRunConcurrentlyAndFailExceptionIsPropogated ( )
172172 {
173- var enter1 = new ManualResetEvent ( false ) ;
174- var enter2 = new ManualResetEvent ( false ) ;
175- var factory = new ManualResetEvent ( false ) ;
176- var resume = new ManualResetEvent ( false ) ;
177-
178- var atomicFactory = new AtomicFactory < int , int > ( ) ;
179- var throwCount = 0 ;
180-
181- Task < int > first = Task . Run ( ( ) =>
182- {
183- enter1 . Set ( ) ;
184- return atomicFactory . GetValue ( 1 , k =>
173+ int count = 0 , timesContended = 0 ;
174+
175+ // Overlapping the value factory calls is hard to achieve reliably.
176+ // Therefore, try many times and verify it was possible to provoke
177+ // at least once.
178+ while ( count ++ < 256 )
179+ {
180+ var enter1 = new ManualResetEvent ( false ) ;
181+ var enter2 = new ManualResetEvent ( false ) ;
182+ var factory = new ManualResetEvent ( false ) ;
183+ var resume = new ManualResetEvent ( false ) ;
184+
185+ var atomicFactory = new AtomicFactory < int , int > ( ) ;
186+ var throwCount = 0 ;
187+
188+ Task < int > first = Task . Run ( ( ) =>
185189 {
186- factory . Set ( ) ;
187- resume . WaitOne ( ) ;
188-
189- Interlocked . Increment ( ref throwCount ) ;
190- throw new Exception ( ) ;
190+ enter1 . Set ( ) ;
191+ return atomicFactory . GetValue ( 1 , k =>
192+ {
193+ factory . Set ( ) ;
194+ resume . WaitOne ( ) ;
195+
196+ Interlocked . Increment ( ref throwCount ) ;
197+ throw new Exception ( ) ;
198+ } ) ;
191199 } ) ;
192- } ) ;
193200
194- Task < int > second = Task . Run ( ( ) =>
195- {
196- enter2 . Set ( ) ;
197- return atomicFactory . GetValue ( 1 , k =>
201+ Task < int > second = Task . Run ( ( ) =>
198202 {
199- factory . Set ( ) ;
200- resume . WaitOne ( ) ;
201-
202- Interlocked . Increment ( ref throwCount ) ;
203- throw new Exception ( ) ;
203+ enter2 . Set ( ) ;
204+ return atomicFactory . GetValue ( 1 , k =>
205+ {
206+ factory . Set ( ) ;
207+ resume . WaitOne ( ) ;
208+
209+ Interlocked . Increment ( ref throwCount ) ;
210+ throw new Exception ( ) ;
211+ } ) ;
204212 } ) ;
205- } ) ;
206213
207- enter1 . WaitOne ( ) ;
208- enter2 . WaitOne ( ) ;
209- factory . WaitOne ( ) ;
210- resume . Set ( ) ;
214+ enter1 . WaitOne ( ) ;
215+ enter2 . WaitOne ( ) ;
216+ factory . WaitOne ( ) ;
217+ resume . Set ( ) ;
211218
212- Func < Task > act1 = ( ) => first ;
213- Func < Task > act2 = ( ) => second ;
219+ Func < Task > act1 = ( ) => first ;
220+ Func < Task > act2 = ( ) => second ;
214221
215- await act1 . Should ( ) . ThrowAsync < Exception > ( ) ;
216- await act2 . Should ( ) . ThrowAsync < Exception > ( ) ;
222+ await act1 . Should ( ) . ThrowAsync < Exception > ( ) ;
223+ await act2 . Should ( ) . ThrowAsync < Exception > ( ) ;
224+
225+ if ( throwCount == 1 )
226+ {
227+ timesContended ++ ;
228+ }
229+ }
217230
218- // verify only one exception was thrown
219- throwCount . Should ( ) . Be ( 1 ) ;
231+ timesContended . Should ( ) . BeGreaterThan ( 0 ) ;
220232 }
221233
222234 [ Fact ]
0 commit comments